C không phải là tập con của C ++ ở đâu? [đóng cửa]


116

Tôi đọc trong rất nhiều cuốn sách rằng C là tập con của C ++.

Một số sách nói rằng C là tập con của C ++, ngoại trừ các chi tiết nhỏ .

Một số trường hợp khi mã sẽ biên dịch trong C, nhưng không phải C ++ là gì?

Câu trả lời:


135

Nếu bạn so sánh C89vớiC++ thì đây là một vài điều

Không có định nghĩa dự kiến ​​trong C ++

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

int [] và int [N] không tương thích (không có loại tương thích trong C ++)

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

Không có kiểu định nghĩa hàm K & R

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

Nested struct có phạm vi lớp trong C ++

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

Không có int mặc định

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

C99 thêm rất nhiều trường hợp khác

Không có xử lý đặc biệt của các chỉ định khai báo trong kích thước mảng của các tham số

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

Không có mảng chiều dài thay đổi

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

Không có thành viên mảng linh hoạt

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

Không giới hạn vòng loại để giúp phân tích răng cưa

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

@mehrdad, cảm ơn. oO không biết người ta phải tạo một biến khi khai báo một cấu trúc lồng nhau trong C. Đã sửa.
Julian Schaub - litb

3
Có một cái khác (vô dụng) từ C89 đến C ++: typedef;là một TU hợp pháp trong C, nhưng không có trong C ++.
Flexo

Lưu ý rằng auto a;hợp lệ trong bản sửa đổi tiêu chuẩn C ++ mới nhất.
fuz

3
@FUZxxl thật sao? Loại suy ra sẽ là agì?
Julian Schaub - litb

3
@FUZxxl ah cảm ơn. Vì vậy, auto x;không hợp lệ trong phiên bản mới nhất, nhưng ví dụ auto x = 0;là. Lúc đầu tôi đã hơi sốc :)
Johannes Schaub - litb

50

Trong C, sizeof('a')bằng sizeof(int).

Trong C ++, sizeof('a')bằng sizeof(char).


46
Điều đó có thể được mô phỏng thành: Trong C, 'a'là một int. Trong C ++, 'a'là một char.
pmg

38

C ++ cũng có từ khóa mới. Sau đây là mã C hợp lệ nhưng sẽ không được biên dịch theo C ++:

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

1
đó là sự thật, nhưng đó chính xác là ý nghĩa của tập hợp con.
yeyeyerman

20
@yeyeyerman: Không. Để nó là tập hợp con, tất cả mã C cũng phải là C ++ hợp lệ. Mã trong ví dụ này là C hợp lệ nhưng không phải C ++.
jalf

24
Không, nếu C là tập con nghiêm ngặt của C ++, thì mọi chương trình C sẽ là chương trình C ++ hợp lệ, nhưng điều đó không đúng. Câu hỏi là tại sao nó không đúng và đây là một ví dụ về lý do tại sao.
Graeme Perrow

Hà! Đừng nghĩ về điều này!
Gab Royer

20

Có rất nhiều thứ. Chỉ là một ví dụ đơn giản (cần đủ để chứng minh C không phải là tập con đúng của C ++):

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

nên biên dịch trong C nhưng không phải trong C ++.


3
C ++ nên yêu cầu một diễn viên rõ ràng để int*.
Mehrdad Afshari

8
Câu trả lời dài: trả về malloc void *, trong C có thể được gán cho bất kỳ loại con trỏ nào và C ++ không thể được gán cho bất kỳ loại con trỏ nào khác.
Daniel Earwicker

5
Imagist: trình biên dịch C, như được định nghĩa theo tiêu chuẩn ANSI C89, không nên phàn nàn.
Mehrdad Afshari

7
Đó là hợp pháp C. Dàn diễn viên là không cần thiết, có thể bị sai và che đậy việc không bao gồm <stdlib.h>. Tôi coi tuyên bố của Mehrdad là cách viết đúng trong C.
David Thornley

16
@Imagist: Tôi thường nghe thấy điều ngược lại từ các lập trình viên C. Họ coi đó là phong cách nghèo nàn để thêm diễn viên, vì nó có thể che giấu lỗi. Mã C tốt không sử dụng diễn viên.
jalf

16

Trong C ++, nếu bạn khai báo a struct,union hoặc enum, tên của nó là ngay lập tức truy cập mà không cần bất kỳ vòng loại:

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

Trong C, điều này sẽ không hoạt động, vì các loại do đó được khai báo sống trong các không gian tên riêng biệt của chúng. Vì vậy, bạn phải viết:

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

Lưu ý sự hiện diện của structcó trên dòng thứ hai. Bạn phải làm tương tự cho unionenum(sử dụng các từ khóa tương ứng của họ) hoặc sử dụngtypedef mẹo:

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

Do đó, bạn có thể có một số loại khác nhau được đặt tên giống nhau trong C, vì bạn có thể định hướng:

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

struct foo x;
foo y;

Tuy nhiên, trong C ++, mặc dù bạn có thể đặt tiền tố một structtên với từ khóa structbất cứ khi nào bạn tham chiếu nó, các không gian tên được hợp nhất và do đó đoạn mã C ở trên không hợp lệ. Mặt khác, C ++ đặc biệt tạo một ngoại lệ để cho phép một loại và một typedef cho loại đó có cùng tên (rõ ràng là không có tác dụng), để cho phép sử dụng typedefthủ thuật không thay đổi từ C.


1
Ví dụ cuối cùng của bạn là hợp lệ C: Ba thẻ ( struct, unionenum) chia sẻ cùng không gian tên. Một ví dụ tốt hơn sẽ làstruct foo { ... }; typedef enum { ... } foo;
schot

@schot: bạn tất nhiên là đúng, cảm ơn bạn đã sửa chữa. Cập nhật.
Pavel Minaev

8

Điều này cũng phụ thuộc vào loại C bạn đang sử dụng. Stroustrup làm cho C ++ tương thích nhất có thể, và không tương thích hơn, với các tiêu chuẩn ISO ANSI và 1990, và phiên bản 1995 không thay đổi gì. Ủy ban C đã đi theo một hướng khác với tiêu chuẩn năm 1999 và ủy ban C ++ đã thay đổi tiêu chuẩn C ++ tiếp theo (có thể ra vào năm tới hoặc lâu hơn) để phù hợp với một số thay đổi.

Stroustrup liệt kê sự không tương thích với C90 / C95 trong Phụ lục B.2 của "Ngôn ngữ lập trình C ++", Phiên bản đặc biệt (là phiên bản thứ 3 với một số tài liệu được thêm vào):

'a'là một inttrong C, mộtchar trong C ++.

Kích thước của một enum là int bằng C, không nhất thiết phải bằng C ++.

C ++ có // bình luận đến cuối dòng, C không (mặc dù đó là một phần mở rộng phổ biến).

Trong C ++, một struct foo {định nghĩa đặt foovào không gian tên toàn cục, trong khi trong C, nó sẽ phải được gọi là struct foo. Điều này cho phép một structđịnh nghĩa che mờ một tên trong phạm vi bên ngoài và có một vài hậu quả khác. Ngoài ra, C cho phép phạm vi lớn hơn chostruct định nghĩa và cho phép chúng trong khai báo kiểu trả về và kiểu đối số.

C ++ là khó khăn hơn về các loại nói chung. Nó sẽ không cho phép một số nguyên được gán cho một enumvoid *các đối tượng không thể được gán cho các loại con trỏ khác mà không cần truyền. Trong C, có thể cung cấp trình khởi tạo chồng chéo (char name[5] = "David" trong đó C sẽ loại bỏ ký tự null).

C89 cho phép ẩn inttrong nhiều ngữ cảnh và C ++ thì không. Điều này có nghĩa là tất cả các hàm phải được khai báo trong C ++, trong khi ở C89, người ta thường có thể nhận được bằng cách giả sử intmọi thứ áp dụng trong khai báo hàm.

Trong C, có thể nhảy từ bên ngoài một khối vào bên trong bằng cách sử dụng câu lệnh được gắn nhãn. Trong C ++, điều này không được phép nếu nó bỏ qua một khởi tạo.

C tự do hơn trong liên kết bên ngoài. Trong C, một constbiến toàn cục là ngầm định externvà điều đó không đúng trong C ++. C cho phép một đối tượng dữ liệu toàn cầu được khai báo nhiều lần mà không cầnextern , nhưng điều đó không đúng trong C ++.

Nhiều từ khóa C ++ không phải là từ khóa trong C hoặc #defined trong tiêu đề C tiêu chuẩn.

Ngoài ra còn có một số tính năng cũ của C không còn được coi là phong cách tốt nữa. Trong C, bạn có thể khai báo một hàm với các định nghĩa đối số sau danh sách các đối số. Trong C, một tuyên bố nhưint foo() có nghĩa là foo()có thể lấy bất kỳ số lượng bất kỳ loại đối số nào, trong khi trong C ++, nó tương đương với int foo(void).

Điều đó dường như bao gồm tất cả mọi thứ từ Stroustrup.


Chúng ta đừng quên thực tế rằng, trong C, bạn phải khai báo các biến ở đầu một phạm vi (nghĩa là ngay sau dấu ngoặc mở), trong khi đó, C ++ cho phép khai báo biến ở bất cứ đâu.
RobH

4
Tuy nhiên, đó là điều mà C ++ có thể làm mà C không thể. Tôi nghĩ rằng chúng tôi đang xem xét những điều bạn có thể làm trong C nhưng không phải C ++.
David Thornley

2
@RobH: Điều đó đúng với C89 nhưng không đúng với C99.
jamesdlin

6

Nếu bạn sử dụng gcc, bạn có thể sử dụng cảnh báo -Wc++-compat để đưa ra cảnh báo về mã C không rõ ràng trong C ++ theo một cách nào đó. Hiện tại nó được sử dụng trong gcc và gần đây nó đã tốt hơn rất nhiều (có thể thử phiên bản hàng đêm để có được thứ tốt nhất có thể).

(Điều này không trả lời đúng câu hỏi, nhưng dân gian có thể thích nó).


1
Tôi nghĩ rằng tôi sẽ không bao giờ đưa ra câu trả lời không trả lời
eharo2

4

Sự khác biệt lớn nhất tôi nghĩ là đây là một tệp nguồn C hợp lệ:

int main()
{
    foo();
}

Lưu ý rằng tôi chưa khai báo foo bất cứ nơi nào.

Bên cạnh sự khác biệt về ngôn ngữ, C ++ cũng thực hiện một số thay đổi đối với thư viện mà nó được thừa hưởng từ C, ví dụ như một số hàm trả về const char *thay vì char *.


Đúng, nguyên mẫu không được yêu cầu trong C nhưng nó thường được coi là thực hành xấu để không sử dụng chúng.
Robert Gamble

1
Bạn nên làm s,C,C89,và lưu ý rằng đó là một tệp nguồn C99 không hợp lệ.
Julian Schaub - litb

Nó không hợp lệ hay chỉ bị phản đối trong C99?
jalf

2
@jalf dự thảo C99 ghi lại các thay đổi đối với C89 và bao gồm cả "xóa int ẩn" và "xóa khai báo hàm ẩn".
Julian Schaub - litb


2

Một số câu trả lời ở đây bao gồm các khác biệt về cú pháp sẽ khiến trình biên dịch C ++ không thành công trên mã nguồn C89 (hoặc C99). Tuy nhiên, có một số khác biệt ngôn ngữ tinh tế là hợp pháp trong cả hai ngôn ngữ nhưng điều đó sẽ tạo ra hành vi khác nhau. Sự sizeof (char)khác biệt mà Naveen đã đề cập là một ví dụ, nhưng Viết chương trình sẽ in "C" nếu được biên dịch thành chương trình (ANSI) C và "C ++" nếu được biên dịch thành chương trình C ++ liệt kê một số chương trình khác.


-2

Trình biên dịch C thường cho phép cắt một góc nhỏ mà C ++ không có. C ++ nghiêm ngặt hơn nhiều so với C. Và nói chung, một số khác biệt này phụ thuộc vào trình biên dịch. g ++ cho phép một số thứ mà trình biên dịch Intel C ++ không có, chẳng hạn. Ngay cả mã C được viết khá tốt cũng sẽ không được biên dịch với trình biên dịch C ++ hiện đại.


-2

Bạn không thể so sánh các ngôn ngữ chỉ theo cú pháp. Nếu bạn làm điều đó có lẽ bạn có thể thấy C là tập con của C ++. Theo tôi, thực tế rằng C ++ là OO (và C không) là đủ để nói rằng C và C ++ là các ngôn ngữ khác nhau.


2
Sai lầm. C ++ không chỉ là OO. Bạn có thể nghĩ C ++ giống như "C ++ = C + OO + lập trình chung + tiền thưởng". Nói cách khác, "C & C ++ ~ = C" trong đó ~ = có nghĩa là gần như bằng nhau.
paercebal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.