2012-05-05 35 views
54

Câu hỏi này được kích hoạt bởi replie (s) đến một post by Herb Sutter nơi ông giải thích quyết định của MS không hỗ trợ/thực hiện một trình biên dịch C99 nhưng chỉ đi với C (99) tính năng trong C++ (11) tiêu chuẩn anyway.Sự khác biệt không tương thích giữa các điểm C (99) và C++ (11) là gì?

Một commenter replied:

(...) C là quan trọng và xứng đáng có ít nhất một chút của sự chú ý.

Có rất nhiều mã hiện có ở đó có giá trị C nhưng không phải là hợp lệ C++. Mã đó không có khả năng được viết lại (...)

Vì tôi chỉ có chương trình trong MS C++, tôi thực sự không biết "thuần túy" C, vâng, tôi chưa có hình ảnh chi tiết về C++ - ngôn ngữ tôi đang sử dụng không có trong C (99) và tôi có ít manh mối mà một số mã C99 sẽ không hoạt động như trong trình biên dịch C++.

Lưu ý rằng tôi biết về C99 chỉ restrict từ khóa mà đối với tôi có vẻ là để có ứng dụng rất hẹp và về các mảng có độ dài thay đổi (trong đó tôi không biết mức độ phổ biến hoặc quan trọng của chúng).

Ngoài ra, tôi rất quan tâm liệu có bất kỳ sự khác biệt quan trọng hoặc gotchas, đó là, C (99) mã sẽ biên dịch dưới C++ (11) nhưng làm điều gì đó khác với trình biên dịch C++ hơn với Trình biên dịch C.


liên kết nhanh: các nguồn lực bên ngoài từ các câu trả lời:

+8

C++ 11 có hỗ trợ các mảng có độ dài biến không? C99, vì vậy nếu không, đó là một ví dụ khá tốt. –

+2

http://david.tribble.com/text/cdiffs.htm - rất nhiều trong số đó vẫn còn hợp lệ cho C++ 11. @CodyGray: VLAs không phải là một phần của C++ 11. – Mat

+1

@CodyGray: C++ 11 không hỗ trợ VLA, vì vậy nhận xét của bạn có thể là câu trả lời :) –

Trả lời

26

Nếu bạn bắt đầu từ tập hợp con chung của C và C++, đôi khi được gọi là C sạch (mà không phải là khá C90), bạn phải xem xét 3 loại không tương thích:

  1. bổ sung C++ featues mà làm hợp pháp C bất hợp pháp C++

    Ví dụ cho đây là từ khóa C++ có thể được sử dụng làm số nhận dạng trong C hoặc chuyển đổi ẩn trong C nhưng yêu cầu trích xuất rõ ràng trong C++.

    Đây có lẽ là lý do chính tại sao Microsoft vẫn vận chuyển giao diện C ở tất cả: nếu không, mã kế thừa không biên dịch như C++ sẽ phải được viết lại.

  2. tính năng C bổ sung mà không phải là một phần của C++

    Ngôn ngữ C đã không ngừng phát triển sau khi C++ được chia hai. Một số ví dụ là các mảng có độ dài thay đổi, các trình khởi tạo được chỉ định và restrict. Những tính năng này có thể khá tiện dụng, nhưng không phải là một phần của tiêu chuẩn bất kỳ C++, và một số trong số họ có thể sẽ không bao giờ làm cho nó trong.

  3. Các tính năng có sẵn trong cả hai C và C++, nhưng có ngữ nghĩa khác nhau

    Ví dụ về điều này sẽ là liên kết của các đối tượng const hoặc inline.

Danh sách không tương thích giữa C99 và C++ 98 can be found here (đã được đề cập bởi Mat).

Khi C++ 11 và C11 trở nên gần hơn ở một số mặt trước (Macro biến thiên hiện có trong C++, mảng biến đổi độ dài giờ đây là tính năng ngôn ngữ C tùy chọn), danh sách không tương thích đã phát triển. trong C và auto loại-specifier trong C++). Là một sang một bên, trong khi Microsoft đã có một số nhiệt cho quyết định từ bỏ C (mà không phải là một trong những gần đây), theo như tôi biết không ai trong cộng đồng nguồn mở đã thực sự thực hiện các bước để làm một cái gì đó về nó : Nó sẽ khá có thể để cung cấp nhiều tính năng của C hiện đại thông qua một trình biên dịch C-to-C++, đặc biệt là nếu bạn xem xét rằng some of them are trivial to implement. Điều này thực sự có thể ngay bây giờ bằng cách sử dụng Comeau C/C++, mà không hỗ trợ C99. Tuy nhiên, nó không thực sự là một vấn đề bức xúc: Cá nhân tôi khá thoải mái khi sử dụng GCC và Clang trên Windows, và có những lựa chọn thay thế độc quyền cho MSVC, ví dụ như Pelles C hoặc trình biên dịch của Intel.

29

Có một loạt các sự không tương thích xung quanh với độ tuổi (C90 o r trước đó), cũng như một loạt các tính năng thực sự tốt đẹp trong C99 và C11. Đây là tất cả ra khỏi đỉnh đầu của tôi.

// Valid C 
int *array = malloc(sizeof(*array) * n); 

// Valid C and valid C++, extra typing, it's always extra typing... 
int *array = (int *) malloc(sizeof(*array) * n); 

// Valid C++ 
int *array = new int[n]; 

C99 là tốt đẹp và các lập trình viên C ở khắp mọi nơi nên sử dụng nó

Các tính năng mới trong C99 là rất tốt đẹp cho lập trình nói chung. VLAs và restrict không (theo ý kiến ​​của tôi) nhắm mục tiêu sử dụng chung, nhưng chủ yếu là để đưa FORTRAN và các lập trình viên số tới C (mặc dù restrict giúp bộ tự động hóa). Vì bất kỳ chương trình phù hợp nào sử dụng restrict sẽ vẫn hoạt động chính xác theo cùng một cách (nhưng có thể không nhanh) nếu bạn #define restrict ở đầu tệp, nó không phải là vấn đề lớn. VLAs là khá hiếm trong tự nhiên có vẻ như.

Thành viên mảng linh hoạt có thể đẹp. Lưu ý rằng chúng KHÔNG giống như các mảng có độ dài thay đổi! Mọi người đã sử dụng thủ thuật này trong nhiều năm, nhưng hỗ trợ chính thức có nghĩa là ít đánh máy hơn và nó cũng cho phép chúng tôi tạo các hằng số lúc biên dịch. (Cách cũ là có một mảng có kích thước 1, nhưng sau đó tính toán kích thước phân bổ là một sự phiền phức thực sự.)

struct lenstr { 
    unsigned length; 
    char data[]; 
}; 
// compile time constant 
const struct lenstr hello = { 12, "hello, world" }; 

Trình khởi tạo được chỉ định. Tiết kiệm rất nhiều đánh máy.

struct my_struct { int a; char *b; int c; const char *d; }; 
struct my_struct x = { 
    .a = 15, 
    .d = "hello" 
    // implicitly sets b = NULL and c = 0 
}; 
int hex_digits[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, /* etc */ ['f'] = 15 }; 

Các inline từ khóa cư xử khác nhau, bạn có thể chọn dịch đơn vị nhận được một phiên bản không-inline của một hàm tuyên bố nội tuyến bằng cách thêm một tuyên bố extern để đơn vị đó.

Chữ hợp chất.

struct point { float x; float y; }; 
struct point xy_from_polar(float r, float angle) 
{ 
    return (struct point) { cosf(angle) * r, sinf(angle) * r }; 
} 

Các snprintf chức năng có lẽ trong 10 chức năng thư viện hữu ích nhất đầu của tôi trong C. Nó không chỉ thiếu từ C++, nhưng thời gian chạy MSVC chỉ cung cấp một chức năng gọi là _snprintf, mà không đảm bảo thêm một NUL terminator vào chuỗi. (snprintf là trong C++ 11, nhưng vẫn vắng mặt thời gian chạy MSVC C.)

cấu trúc Anonymous và đoàn (C11, nhưng GCC mở rộng kể từ mãi mãi) (công đoàn vô danh là rõ ràng trong C + 03, không có hỗ trợ MSVC trong chế độ C):

struct my_value { 
    int type; 
    union { 
     int as_int; 
     double as_double; 
    }; // no field name! 
}; 

Như bạn có thể thấy, rất nhiều các tính năng chỉ giúp bạn tiết kiệm rất nhiều cách gõ (literals hợp chất), hoặc thực hiện các chương trình dễ dàng hơn để gỡ lỗi (thành viên mảng linh hoạt) , làm cho nó dễ dàng hơn để tránh những sai lầm (được chỉ định initializers/quên để khởi tạo các lĩnh vực cấu trúc). Đây không phải là những thay đổi mạnh mẽ.

Đối với sự khác biệt ngữ nghĩa, tôi chắc chắn rằng quy tắc bí danh là khác nhau, nhưng hầu hết các trình biên dịch đều tha thứ đủ trong những ngày này tôi không chắc chắn cách bạn xây dựng một trường hợp thử nghiệm để chứng minh. Sự khác biệt giữa C và C++ mà mọi người đạt được là biểu thức sizeof('a') cũ, luôn là 1 cho C++ nhưng thường là 4 trên hệ thống C 32 bit. Nhưng không ai quan tâm những gì sizeof('a') là anyway. Tuy nhiên, có một số đảm bảo trong tiêu chuẩn C99 để mã hóa các thực hành hiện có.

Lấy mã sau đây. Nó sử dụng một thủ thuật phổ biến để xác định các loại công đoàn trong C mà không lãng phí thêm dung lượng lưu trữ. Tôi nghĩ rằng đây là ngữ nghĩa hợp lệ C99 và I nghĩ rằng đây là ngữ nghĩa không rõ ràng C++, nhưng tôi có thể sai.

#define TAG_FUNKY_TOWN 5 
struct object { int tag; }; 
struct funky_town { int tag; char *string; int i; }; 
void my_function(void) 
{ 
    struct object *p = other_function(); 
    if (p->tag == TAG_FUNKY_TOWN) { 
     struct funky_town *ft = (struct funky_town *) p; 
     puts(ft->string); 
    } 
} 

Thật đáng tiếc. Trình tạo mã MSVC đẹp, quá tệ không có giao diện người dùng C99.

+1

C99 không cho phép khởi tạo thành viên mảng linh hoạt (đó là phần mở rộng GNU). C++ 11 có khởi tạo đồng bộ, tương tự như các chữ cái hợp chất: 'return {cos (góc) * r, sin (góc) * r};'. các công đoàn ẩn danh là hợp lệ C++. Tôi không chắc chắn rằng các cấu trúc ẩn danh thậm chí còn hợp lệ C mặc dù (và chúng dường như vô nghĩa đối với tôi). Tôi nghĩ rằng 'C++ ngữ nghĩa đáng ngờ' hợp lệ, nhưng tôi có thể sai. – bames53

+5

Ngoài ra C++ là tốt đẹp và lập trình C ở khắp mọi nơi nên sử dụng nó. ;) – bames53

+0

"Từ khóa nội tuyến hoạt động khác nhau, bạn có thể chọn đơn vị dịch được phiên bản không nội tuyến của hàm được khai báo nội tuyến bằng cách thêm khai báo extern vào đơn vị đó.". Và không may là bạn [** có **] (http://stackoverflow.com/questions/2217628/multiple-definition-of-inline-functions-when-linking-static-libs/2218034#2218034) chọn :( –

2

Trong C++, thiết lập một thành viên của liên minh và truy cập giá trị của một thành viên khác là hành vi không xác định, trong khi nó không được xác định trong C99.

Có rất nhiều sự khác biệt khác được liệt kê trên wikipedia page.

+0

Tôi nghĩ đây cũng là UB trong C99 và nó chỉ là OpenCL C (dựa trên C99) đã làm giảm hạn chế này một chút. –

+1

@ChristianRau: http: //stackoverflow.com/a/8513748/48015 – Christoph

+0

Phần [wikipedia section} (http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B#Constructs_valid_in_C_but_not_C.2B.2B) thực sự là khá đẹp. Tôi nên thực hiện thói quen truy cập wikipedia trước khi hỏi tại đây. :-) –

2

Tôi sẽ đề cập đến "C.1 C++ và ISO C" của C++11 standard. Tài liệu đó có một cú đánh bằng cách thổi bay từng khác biệt và tác động của nó đối với sự phát triển.