C ไม่ใช่ส่วนย่อยของ C ++ อยู่ที่ไหน [ปิด]


116

ฉันอ่านหนังสือหลายเล่มที่ C เป็นส่วนย่อยของ C ++

หนังสือบางเล่มบอกว่า C เป็นส่วนหนึ่งของ C ++ ยกเว้นสำหรับรายละเอียดเล็ก ๆ น้อย ๆ

มีกรณีใดบ้างที่โค้ดจะคอมไพล์ใน C แต่ไม่ใช่ C ++

คำตอบ:


135

หากคุณเปรียบเทียบC89กับC++นี่คือสองสิ่ง

ไม่มีคำจำกัดความเบื้องต้นใน C ++

int n;
int n; // ill-formed: n already defined

int [] และ int [N] ไม่เข้ากัน (ไม่มีประเภทที่เข้ากันได้ใน C ++)

int a[1];
int (*ap)[] = &a; // ill-formed: a does not have type int[]

ไม่มีลักษณะการกำหนดฟังก์ชัน K&R

int b(a) int a; { } // ill-formed: grammar error

โครงสร้างที่ซ้อนกันมีขอบเขตคลาสใน C ++

struct A { struct B { int a; } b; int c; };
struct B b; // ill-formed: b has incomplete type (*not* A::B)

ไม่มี int เริ่มต้น

auto a; // ill-formed: type-specifier missing

C99 เพิ่มกรณีอื่น ๆ มากมาย

ไม่มีการจัดการพิเศษของตัวระบุการประกาศในขนาดอาร์เรย์ของพารามิเตอร์

// ill-formed: invalid syntax
void f(int p[static 100]) { }

ไม่มีอาร์เรย์ความยาวตัวแปร

// ill-formed: n is not a constant expression
int n = 1;
int an[n];

ไม่มีสมาชิกอาร์เรย์ที่ยืดหยุ่น

// ill-formed: fam has incomplete type
struct A { int a; int fam[]; }; 

ไม่มีคุณสมบัติ จำกัด สำหรับช่วยในการวิเคราะห์นามแฝง

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);

@mehrdad ขอบคุณ oO ไม่รู้ว่าต้องสร้างตัวแปรอยู่แล้วเมื่อประกาศโครงสร้างที่ซ้อนกันใน C Fixed
Johannes Schaub - litb

3
มี C89 ถึง C ++ อีกอัน (ไร้ประโยชน์): typedef;เป็น TU ตามกฎหมายใน C แต่ไม่ใช่ใน C ++
Flexo

สังเกตว่าauto a;ใช้ได้ในการแก้ไขมาตรฐาน C ++ ใหม่ล่าสุด
fuz

3
@FUZxxl จริงหรือ? ประเภทอนุมานได้aคืออะไร?
Johannes Schaub - litb

3
@FUZxxl อาขอบคุณ ดังนั้นจึงauto x;ไม่ถูกต้องในการแก้ไขล่าสุด แต่ตัวอย่างเช่นauto x = 0;คือ ตอนแรกตกใจนิดหน่อย :)
Johannes Schaub - litb

50

ใน C, มีค่าเท่ากับsizeof('a')sizeof(int)

ใน C ++ sizeof('a')มีค่าเท่ากับsizeof(char).


46
ที่สามารถย่อเป็น: ใน C 'a'คือintไฟล์. ใน C ++ 'a'คือไฟล์char.
pmg

38

C ++ มีคำหลักใหม่เช่นกัน ต่อไปนี้เป็นรหัส C ที่ถูกต้อง แต่จะไม่รวบรวมภายใต้ C ++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;

1
มันเป็นความจริง แต่นั่นคือความหมายของชุดย่อย
yeyeyerman

20
@yeyeyerman: ไม่เพื่อให้เป็นส่วนย่อยรหัส C ทั้งหมดจะต้องเป็น C ++ ที่ถูกต้องเช่นกัน โค้ดในตัวอย่างนี้คือ C ที่ถูกต้อง แต่ไม่ใช่ C ++
jalf

24
ไม่ถ้า C เป็นส่วนย่อยที่เข้มงวดของ C ++ โปรแกรม C ทุกโปรแกรมจะเป็นโปรแกรม C ++ ที่ถูกต้อง แต่นั่นไม่เป็นความจริง คำถามคือเหตุใดจึงไม่เป็นความจริงและนี่คือตัวอย่างหนึ่งของสาเหตุ
Graeme Perrow

ฮา! ไม่ได้คิดถึงเรื่องนี้!
Gab Royer

20

มีมากมายเต็มไปหมด เป็นเพียงตัวอย่างง่ายๆ (ควรจะเพียงพอที่จะพิสูจน์ว่า C ไม่ใช่ส่วนย่อยที่เหมาะสมของ C ++):

int* test = malloc(100 * sizeof(int));

ควรคอมไพล์ในภาษา C แต่ไม่ใช่ใน C ++


3
c ++ int*ควรจะต้องมีนักแสดงอย่างชัดเจนในการ
Mehrdad Afshari

8
คำตอบแบบยาว: ผลตอบแทน malloc void *ซึ่งใน C สามารถกำหนดให้กับชนิดตัวชี้ใดก็ได้และไม่สามารถกำหนด C ++ ให้กับตัวชี้ประเภทอื่นได้
Daniel Earwicker

5
Imagist: คอมไพเลอร์ C ตามที่กำหนดโดยมาตรฐาน ANSI C89 ไม่ควรบ่น
Mehrdad Afshari

7
เป็นสิ่งที่ถูกกฎหมาย C. การคัดเลือกนักแสดงไม่จำเป็นมีความเป็นไปได้ที่จะทำผิดและปกปิดความล้มเหลวในการรวม <stdlib.h> ฉันคิดว่าคำพูดของ Mehrdad เป็นวิธีที่ถูกต้องในการเขียนใน C.
David Thornley

16
@Imagist: ฉันมักจะได้ยินสิ่งที่ตรงกันข้ามกับโปรแกรมเมอร์ C พวกเขาคิดว่าเป็นรูปแบบที่ไม่ดีในการเพิ่มนักแสดงเนื่องจากอาจปกปิดจุดบกพร่อง รหัส Good C ไม่ใช้การร่าย
jalf

16

ใน C ++ ถ้าคุณประกาศstruct, unionหรือenumชื่อของมันสามารถเข้าถึงได้ทันทีโดยไม่บ่นใด ๆ

struct foo { ... };
foo x; // declare variable

ในภาษา C จะใช้ไม่ได้เนื่องจากประเภทที่ประกาศอยู่ในเนมสเปซเฉพาะของตัวเอง ดังนั้นคุณต้องเขียน:

struct foo { ... };
struct foo x; // declare variable

สังเกตว่าstructมีอยู่ที่บรรทัดที่สอง คุณต้องทำเช่นเดียวกันสำหรับunionและenum(โดยใช้คำหลักที่เกี่ยวข้อง) หรือใช้typedefเคล็ดลับ:

typedef struct { ... } foo;
foo x; // declare variable

ดังนั้นคุณสามารถตั้งชื่อประเภทต่างๆได้หลายประเภทเหมือนกันใน C เนื่องจากคุณสามารถทำให้ไม่ชัดเจน:

struct foo { ... };
typedef enum { ... } foo;

struct foo x;
foo y;

อย่างไรก็ตามใน C ++ แม้ว่าคุณจะสามารถนำหน้าstructชื่อด้วยคำหลักได้structทุกเมื่อที่คุณอ้างอิง แต่เนมสเปซจะถูกรวมเข้าด้วยกันดังนั้นข้อมูลโค้ด C ด้านบนจึงไม่ถูกต้อง ในทางกลับกัน C ++ ให้ข้อยกเว้นโดยเฉพาะเพื่อให้ประเภทและ typedef สำหรับประเภทนั้นมีชื่อเดียวกัน (เห็นได้ชัดว่าไม่มีผลใด ๆ ) เพื่อให้การใช้typedefเคล็ดลับไม่เปลี่ยนแปลงจาก C


1
ตัวอย่างสุดท้ายของคุณไม่ถูกต้อง C: สามแท็ก ( struct, unionและenum) ส่วน namespace เดียวกัน ตัวอย่างที่ดีกว่าคือstruct foo { ... }; typedef enum { ... } foo;
schot

@schot: คุณคิดถูกแล้วขอบคุณสำหรับการแก้ไข Updated
Pavel Minaev

8

นอกจากนี้ยังขึ้นอยู่กับความหลากหลายของ C ที่คุณใช้ Stroustrup ทำให้ C ++ เข้ากันได้มากที่สุดเท่าที่จะทำได้และไม่มีความเข้ากันได้อีกต่อไปโดยมีมาตรฐาน ISO 1989 ANSI และ 1990 และเวอร์ชัน 1995 ไม่เปลี่ยนแปลงอะไรเลย คณะกรรมการ C ไปในทิศทางที่แตกต่างกันเล็กน้อยกับมาตรฐานปี 1999 และคณะกรรมการ C ++ ได้เปลี่ยนมาตรฐาน C ++ ถัดไป (อาจจะออกในปีหน้าหรือมากกว่านั้น) เพื่อให้สอดคล้องกับการเปลี่ยนแปลงบางอย่าง

Stroustrup แสดงรายการความเข้ากันไม่ได้กับ C90 / C95 ในภาคผนวก B.2 ของ "The C ++ Programming Language" รุ่นพิเศษ (ซึ่งเป็นรุ่นที่ 3 พร้อมเนื้อหาเพิ่มเติมบางส่วน):

'a'เป็นintภาษา C charใน C ++

ขนาดของ enum อยู่intใน C ไม่จำเป็นต้องอยู่ใน C ++

C ++ มี//ความคิดเห็นที่ท้ายบรรทัด C ไม่มี (แม้ว่าจะเป็นส่วนขยายทั่วไปก็ตาม)

ใน C ++ ที่struct foo {ทำให้ความหมายfooลงใน namespace โลกในขณะที่ใน C struct fooก็จะต้องได้รับการเรียกว่า สิ่งนี้ช่วยให้structคำจำกัดความเงาชื่อในขอบเขตภายนอกและมีผลกระทบอื่น ๆ อีกเล็กน้อย นอกจากนี้ C ยังอนุญาตขอบเขตที่ใหญ่กว่าสำหรับstructคำจำกัดความและอนุญาตให้ใช้ในการประกาศประเภทผลตอบแทนและประเภทอาร์กิวเมนต์

C ++ นั้นยุ่งยากกว่าเกี่ยวกับประเภทโดยทั่วไป จะไม่อนุญาตให้กำหนดจำนวนเต็มให้กับ an enumและvoid *ไม่สามารถกำหนดอ็อบเจกต์ให้กับตัวชี้ประเภทอื่นได้หากไม่มีการร่าย ใน C เป็นไปได้ที่จะระบุค่าเริ่มต้นที่ซ้อนทับ ( char name[5] = "David"โดยที่ C จะละทิ้งอักขระว่างต่อท้าย)

C89 อนุญาตโดยปริยายintในหลายบริบทและ C ++ ไม่ได้ ซึ่งหมายความว่าต้องประกาศฟังก์ชันทั้งหมดใน C ++ ในขณะที่ใน C89 มักเป็นไปได้ที่จะได้รับโดยสมมติว่าintทุกสิ่งที่เกี่ยวข้องในการประกาศฟังก์ชัน

ใน C เป็นไปได้ที่จะข้ามจากนอกบล็อกไปสู่ภายในโดยใช้คำสั่งที่มีป้ายกำกับ ใน C ++ สิ่งนี้ไม่ได้รับอนุญาตหากข้ามการเริ่มต้น

C มีความเสรีมากขึ้นในการเชื่อมโยงภายนอก ใน C constตัวแปรโกลบอลเป็นโดยปริยายexternและนั่นไม่เป็นความจริงใน C ++ C อนุญาตให้ประกาศอ็อบเจ็กต์ข้อมูลส่วนกลางได้หลายครั้งโดยไม่มีexternแต่นั่นไม่เป็นความจริงใน C ++

คีย์เวิร์ด C ++ จำนวนมากไม่ใช่คีย์เวิร์ดใน C หรือ#defined อยู่ในส่วนหัว C มาตรฐาน

นอกจากนี้ยังมีคุณสมบัติที่เก่ากว่าของ C ที่ไม่ถือว่าเป็นสไตล์ที่ดีอีกต่อไป ใน C คุณสามารถประกาศฟังก์ชันที่มีนิยามอาร์กิวเมนต์หลังรายการอาร์กิวเมนต์ได้ ใน C, การประกาศเช่นint foo()หมายความว่าfoo()สามารถใช้จำนวนของประเภทของข้อโต้แย้งใด ๆ ในขณะที่ใน C ++ int foo(void)มันเทียบเท่ากับ

ดูเหมือนว่าจะครอบคลุมทุกอย่างตั้งแต่ Stroustrup


อย่าลืมความจริงที่ว่าใน C คุณต้องประกาศตัวแปรที่จุดเริ่มต้นของขอบเขต (เช่นทันทีหลังจากวงเล็บปีกกาเปิด) ในขณะที่ C ++ อนุญาตให้ประกาศตัวแปรได้ทุกที่
RobH

4
อย่างไรก็ตามนั่นคือสิ่งที่ C ++ สามารถทำได้ซึ่ง C ไม่สามารถทำได้ ฉันคิดว่าเรากำลังดูสิ่งต่างๆที่คุณทำได้ใน C แต่ไม่ใช่ C ++
David Thornley

2
@ RobH: นั่นเป็นเรื่องจริงสำหรับ C89 แต่ไม่ใช่สำหรับ C99
jamesdlin

6

หากคุณใช้ gcc คุณสามารถใช้คำเตือน-Wc++-compatเพื่อให้คำเตือนเกี่ยวกับรหัส C ที่น่าสงสัยใน C ++ ได้ไม่ทางใดก็ทางหนึ่ง ปัจจุบันใช้ใน gcc เองและดีขึ้นมากเมื่อเร็ว ๆ นี้ (อาจลองใช้เวอร์ชันต่อคืนเพื่อให้ได้สิ่งที่ดีที่สุด)

(สิ่งนี้ไม่ได้ตอบคำถามอย่างเคร่งครัด แต่ชาวบ้านอาจชอบ)


1
ฉันคิดว่าฉันจะไม่มีวัน
โหวต

4

ความแตกต่างที่ใหญ่ที่สุดเพียงอย่างเดียวที่ฉันคิดคือนี่คือไฟล์ต้นฉบับ C ที่ถูกต้อง:

int main()
{
    foo();
}

โปรดทราบว่าฉันไม่ได้ประกาศ fooที่ไหนเลย

นอกเหนือจากความแตกต่างของภาษา C ++ นอกจากนี้ยังทำให้การเปลี่ยนแปลงบางอย่างไปยังห้องสมุดที่จะสืบทอดมาจาก C เช่นฟังก์ชั่นบางอย่างกลับมาแทนconst char *char *


ถูกต้องไม่จำเป็นต้องใช้ต้นแบบใน C แต่โดยปกติถือว่าเป็นการปฏิบัติที่ไม่ดีที่จะไม่ใช้มัน
Robert Gamble

1
คุณควรทำs,C,C89,และสังเกตว่าเป็นซอร์สไฟล์ C99 ที่ไม่ถูกต้อง
Johannes Schaub - litb

มันไม่ถูกต้องหรือเพิ่งเลิกใช้งานใน C99?
jalf

2
@jalf เอกสารฉบับร่าง C99 เกี่ยวกับการเปลี่ยนแปลง C89 และรวมทั้ง "remove implicit int" และ "remove implicit function declaration"
Johannes Schaub - litb

4
#include <stdio.h>

int new (int n) {
    return n/2;
}

int main(void) {
    printf("%d\n", new(10));
    return 0;
}

ดูเพิ่มเติมc ++ คำถามที่พบบ่อยเข้า


2

คำตอบจำนวนหนึ่งที่นี่ครอบคลุมความแตกต่างทางไวยากรณ์ที่อาจทำให้คอมไพเลอร์ C ++ ล้มเหลวในซอร์สโค้ด C89 (หรือ C99) อย่างไรก็ตามมีความแตกต่างทางภาษาเล็กน้อยที่ถูกกฎหมายในทั้งสองภาษา แต่จะทำให้เกิดพฤติกรรมที่แตกต่างกัน ความsizeof (char)แตกต่างที่ Naveen กล่าวถึงเป็นตัวอย่างหนึ่ง แต่เขียนโปรแกรมที่จะพิมพ์ "C" หากคอมไพล์เป็นโปรแกรม C (ANSI) และ "C ++" หากคอมไพล์เป็นโปรแกรม C ++ จะแสดงรายการอื่น ๆ


-2

โดยทั่วไปคอมไพเลอร์ C อนุญาตให้มีการตัดมุมเล็กน้อยที่ C ++ ไม่ทำ C ++ นั้นเข้มงวดกว่า C มากและโดยทั่วไปความแตกต่างเหล่านี้บางส่วนขึ้นอยู่กับคอมไพเลอร์ g ++ อนุญาตบางสิ่งที่คอมไพเลอร์ Intel C ++ ไม่มีเช่น แม้แต่โค้ด C ที่เขียนค่อนข้างดีก็ไม่สามารถคอมไพเลอร์ C ++ ที่ทันสมัยได้


-2

คุณไม่สามารถเปรียบเทียบภาษาด้วยไวยากรณ์เท่านั้น หากคุณทำเช่นนั้นคุณอาจเห็น C เป็นส่วนย่อยของ C ++ ในความคิดของฉันความจริงที่ว่า C ++ คือ OO (และ C ไม่ใช่) ก็เพียงพอที่จะบอกได้ว่า C และ C ++ เป็นภาษาที่แตกต่างกัน


2
ไม่ถูกต้อง. C ++ ไม่ใช่แค่ OO คุณอาจคิดว่า C ++ บางอย่างเช่น "C ++ = C + OO + โปรแกรมทั่วไป + โบนัส" ในอีกวิธีหนึ่ง "C & C ++ ~ = C" โดยที่ ~ = หมายถึงเกือบเท่ากัน
paercebal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.