Mã có thể hợp lệ trong cả C và C ++ có thể tạo ra hành vi khác nhau khi được biên dịch theo từng ngôn ngữ không?


664

C và C ++ có nhiều điểm khác biệt và không phải tất cả mã C hợp lệ đều là mã C ++ hợp lệ.
(Theo "hợp lệ" Tôi có nghĩa là mã tiêu chuẩn với hành vi được xác định, nghĩa là không cụ thể thực hiện / không xác định / v.v.)

Có kịch bản nào trong đó một đoạn mã hợp lệ trong cả C và C ++ sẽ tạo ra hành vi khác nhau khi được biên dịch với trình biên dịch chuẩn trong mỗi ngôn ngữ không?

Để làm cho nó trở thành một so sánh hợp lý / hữu ích (Tôi đang cố gắng học một cái gì đó thực tế hữu ích, không cố gắng tìm ra những sơ hở rõ ràng trong câu hỏi), hãy giả sử:

  • Không có gì liên quan đến tiền xử lý (có nghĩa là không có hack #ifdef __cplusplus, pragma, v.v.)
  • Bất cứ điều gì được định nghĩa triển khai đều giống nhau ở cả hai ngôn ngữ (ví dụ: giới hạn số, v.v.)
  • Chúng tôi đang so sánh các phiên bản hợp lý gần đây của từng tiêu chuẩn (ví dụ: C ++ 98 và C90 trở lên)
    Nếu các phiên bản có vấn đề, thì vui lòng đề cập đến phiên bản nào của mỗi phiên bản tạo ra hành vi khác nhau.

11
Nhân tiện, có thể hữu ích để lập trình theo một phương ngữ là C và C ++ cùng một lúc. Tôi đã làm điều này trong quá khứ và một dự án hiện tại: ngôn ngữ TXR. Thật thú vị, các nhà phát triển ngôn ngữ Lua đã làm điều tương tự, và họ gọi phương ngữ này là "Clean C". Bạn nhận được lợi ích của việc kiểm tra thời gian biên dịch tốt hơn và có thể là các chẩn đoán hữu ích bổ sung từ trình biên dịch C ++, nhưng vẫn giữ được tính di động của C.
Kaz

9
Tôi đã hợp nhất câu hỏi cũ hơn vào câu hỏi này vì câu hỏi này có nhiều lượt xem và câu trả lời nâng cao hơn. Đây vẫn là một ví dụ về một câu hỏi không mang tính xây dựng, nhưng nó khá ranh giới vì có, nó dạy cho người dùng SO một cái gì đó. Tôi đóng nó là không mang tính xây dựng để phản ánh trạng thái của câu hỏi trước khi hợp nhất. Hãy không đồng ý và mở lại.
George Stocker

13
Bỏ phiếu để mở lại như tôi nghĩ nó có thể được trả lời một cách khách quan với câu "có" theo sau là một ví dụ (như đã được chứng minh dưới đây). Tôi nghĩ rằng nó mang tính xây dựng ở chỗ mọi người có thể học hành vi có liên quan từ nó.
Anders Abel

6
@AndersAbel Số lượng câu trả lời thuần túy, tất cả đều đúng, chứng minh rõ ràng rằng nó vẫn là một câu hỏi tạo danh sách. Không có cách nào bạn có thể hỏi câu hỏi này mà không có danh sách.
dmckee --- ex-moderator mèo con

2
@dmckee Vì những gì đáng giá, tôi đồng ý với bạn. Tuy nhiên, C ++ thẻ mọi người ... Chúng ta sẽ nói ... nóng nảy .
George Stocker

Câu trả lời:


397

Điều sau đây, hợp lệ trong C và C ++, sẽ (rất có thể) dẫn đến các giá trị khác nhau itrong C và C ++:

int i = sizeof('a');

Xem Kích thước của ký tự ('a') trong C / C ++ để biết giải thích về sự khác biệt.

Một số khác từ bài viết này :

#include <stdio.h>

int  sz = 80;

int main(void)
{
    struct sz { char c; };

    int val = sizeof(sz);      // sizeof(int) in C,
                               // sizeof(struct sz) in C++
    printf("%d\n", val);
    return 0;
}

8
Chắc chắn là không mong đợi điều này! Tôi đã hy vọng cho một cái gì đó kịch tính hơn một chút nhưng điều này vẫn hữu ích, cảm ơn. :) +1
dùng541686

17
+1 ví dụ thứ hai là một ví dụ tốt cho thực tế là C ++ không yêu cầu structtrước tên cấu trúc.
Seth Carnegie

1
@Andrey Tôi cũng nghĩ như vậy một thời gian trước và đã thử nghiệm nó và nó đã hoạt động trên GCC 4.7.1 mà không có tiêu chuẩn, trái với dự đoán của tôi. Đó có phải là một lỗi trong GCC không?
Seth Carnegie

3
@SethCarnegie: Một chương trình không phù hợp không cần phải hoạt động, nhưng nó cũng không được đảm bảo để hoạt động.
Andrey Vihrov

3
struct sz { int i[2];};sẽ có nghĩa là C và C ++ phải tạo ra các giá trị khác nhau. (Trong khi DSP có sizeof (int) == 1, có thể tạo ra cùng một giá trị).
Martin Bonner hỗ trợ Monica

464

Dưới đây là một ví dụ tận dụng sự khác biệt giữa các lệnh gọi hàm và khai báo đối tượng trong C và C ++, cũng như thực tế là C90 cho phép gọi các hàm không được khai báo:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

int f() {
    return printf("hello");
}

Trong C ++, nó sẽ không in gì vì tạm thời fđược tạo và hủy, nhưng trong C90, nó sẽ in hellovì các hàm có thể được gọi mà không được khai báo.

Trong trường hợp bạn đã tự hỏi về tên f được sử dụng hai lần, các tiêu chuẩn C và C ++ cho phép rõ ràng điều này và để tạo một đối tượng bạn phải nói struct fđể phân tán nếu bạn muốn cấu trúc hoặc bỏ đi structnếu bạn muốn chức năng.


7
Nói đúng theo C điều này sẽ không biên dịch, vì khai báo "int f ()" nằm sau định nghĩa của "int main ()" :)
Sogartar

15
@Sogartar, thật sao? codepad.org/STSQlUhh Trình biên dịch C99 sẽ đưa ra cảnh báo cho bạn, nhưng họ vẫn sẽ cho phép bạn biên dịch nó.
jrajav

22
@Sogartar trong các hàm C được phép khai báo ngầm.
Alex B

11
@AlexB Không có trong C99 và C11.

6
@jrajav Đó không phải là trình biên dịch C99. Trình biên dịch C99 phát hiện các định danh không được khai báo là lỗi cú pháp. Trình biên dịch không làm điều đó là trình biên dịch C89 hoặc trình biên dịch chuẩn hoặc một loại trình biên dịch không tuân thủ khác.

430

Đối với C ++ so với C90, có ít nhất một cách để có các hành vi khác nhau không được xác định. C90 không có nhận xét một dòng. Với một chút quan tâm, chúng ta có thể sử dụng điều đó để tạo một biểu thức với kết quả hoàn toàn khác nhau trong C90 và trong C ++.

int a = 10 //* comment */ 2 
        + 3;

Trong C ++, mọi thứ từ cuối //đến cuối dòng đều là một nhận xét, vì vậy điều này hoạt động như sau:

int a = 10 + 3;

Vì C90 không có nhận xét một dòng, chỉ /* comment */có một nhận xét. Đầu tiên /2cả hai đều là phần khởi tạo, vì vậy nó đi ra:

int a = 10 / 2 + 3;

Vì vậy, một trình biên dịch C ++ chính xác sẽ cung cấp 13, nhưng trình biên dịch C90 hoàn toàn chính xác 8. Tất nhiên, tôi chỉ chọn các số tùy ý ở đây - bạn có thể sử dụng các số khác khi bạn thấy phù hợp.


34
WHOA này thật tuyệt vời !! Trong tất cả những điều có thể tôi sẽ không bao giờ nghĩ rằng bình luận có thể được sử dụng để thay đổi hành vi haha. +1
dùng541686

89
ngay cả khi không có 2, nó sẽ đọc 10 / + 3là hợp lệ (unary +).
Benoit

12
Bây giờ để giải trí, hãy sửa đổi nó để cả C và C ++ đều tính toán các biểu thức số học khác nhau để đánh giá cho cùng một kết quả.
Ryan C. Thompson

21
@RyanThndry tầm thường. s /
2/1

4
@Mehrdad Tôi sai hay nhận xét có liên quan đến tiền xử lý? Do đó, họ nên được loại trừ như một câu trả lời có thể từ câu hỏi của bạn! ;-)
Ale

179

C90 so với C ++ 11 ( intso với double):

#include <stdio.h>

int main()
{
  auto j = 1.5;
  printf("%d", (int)sizeof(j));
  return 0;
}

Trong C autocó nghĩa là biến cục bộ. Trong C90, bạn có thể bỏ qua biến hoặc loại hàm. Nó mặc định là int. Trong C ++ 11 autocó nghĩa là một cái gì đó hoàn toàn khác, nó báo cho trình biên dịch suy ra loại biến từ giá trị được sử dụng để khởi tạo nó.


10
C90 có autogì?
Seth Carnegie

22
@SethCarnegie: Vâng, đó là một lớp lưu trữ; Đó là những gì xảy ra theo mặc định khi bạn bỏ qua nó, vì vậy không ai sử dụng nó và họ đã thay đổi ý nghĩa của nó. Tôi nghĩ đó là intmặc định. Điều này thật thông minh! +1
dùng541686

5
C11 không có ẩn- int.
R .. GitHub DỪNG GIÚP ICE

23
@KeithThndry Ah, tôi đoán bạn có nghĩa là suy ra int. Tuy nhiên, trong thế giới thực, nơi có hàng tấn mã kế thừa và người dẫn đầu thị trường vẫn chưa thực hiện C99 và không có ý định làm điều đó, nói về "một phiên bản C lỗi thời" là vô lý.
Jim Balter

11
"Mỗi biến PHẢI có một lớp lưu trữ rõ ràng. Thực sự, quản lý cấp trên của bạn."
btown

120

Một ví dụ khác mà tôi chưa thấy đề cập đến, ví dụ này nêu bật sự khác biệt của tiền xử lý:

#include <stdio.h>
int main()
{
#if true
    printf("true!\n");
#else
    printf("false!\n");
#endif
    return 0;
}

Điều này in "false" trong C và "true" trong C ++ - Trong C, mọi macro không xác định sẽ đánh giá là 0. Trong C ++, có 1 ngoại lệ: "true" ước tính là 1.


2
Hấp dẫn. Có ai biết lý do đằng sau sự thay đổi này?
antred

3
bởi vì "true" là một từ khóa / giá trị hợp lệ, do đó, nó được đánh giá là đúng như bất kỳ "giá trị thực" nào (giống như bất kỳ số nguyên dương nào). Bạn vẫn có thể làm #define true false để in "false" trong C ++;)
CoffeDeveloper

22
#define true false _ಠ
Bryan Boettcher

2
@DarioOO sẽ không xác định lại kết quả như vậy trong UB?
Ruslan

3
@DarioOO: Vâng, bạn đã sai. Định nghĩa lại từ khóa là không được phép, hình phạt để lại số phận (UB). Bộ tiền xử lý là một giai đoạn biên dịch riêng biệt không chịu được.
Ded repeatator

108

Theo tiêu chuẩn C ++ 11:

a. Toán tử dấu phẩy thực hiện chuyển đổi lvalue-to-rvalue trong C nhưng không phải C ++:

   char arr[100];
   int s = sizeof(0, arr);       // The comma operator is used.

Trong C ++, giá trị của biểu thức này sẽ là 100 và trong C này sẽ là sizeof(char*).

b. Trong C ++, kiểu liệt kê là enum của nó. Trong C, kiểu liệt kê là int.

   enum E { a, b, c };
   sizeof(a) == sizeof(int);     // In C
   sizeof(a) == sizeof(E);       // In C++

Điều này có nghĩa là sizeof(int)có thể không bằng sizeof(E).

c. Trong C ++, một hàm được khai báo với danh sách params trống không có đối số. Trong danh sách params trống C có nghĩa là số lượng và loại tham số hàm không xác định.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C

Cái đầu tiên cũng được định nghĩa triển khai như của Alexey. Nhưng +1.
Seth Carnegie

1
@ Vì vậy, tất cả các tài liệu trên được lấy trực tiếp từ Phụ lục C.1 của tiêu chuẩn C ++ 11.
Kirill Kobelev

Có nhưng nó vẫn được xác định theo thực hiện. sizeof(char*)có thể là 100 trong trường hợp ví dụ đầu tiên tạo ra hành vi có thể quan sát tương tự trong C và C ++ (nghĩa là phương thức thu được ssẽ khác nhau, scuối cùng sẽ là 100). OP đã đề cập rằng loại hành vi được xác định theo triển khai này là tốt vì anh ta chỉ muốn tránh các câu trả lời của luật sư ngôn ngữ, do đó, hành vi đầu tiên là ổn bởi ngoại lệ của anh ta. Nhưng thứ hai là tốt trong mọi trường hợp.
Seth Carnegie

5
Có một cách khắc phục dễ dàng - chỉ cần thay đổi ví dụ thành:char arr[sizeof(char*)+1]; int s = sizeof(0, arr);
Mankude

5
Để tránh sự khác biệt do triển khai thực hiện, bạn cũng có thể sử dụng void *arr[100]. Trong trường hợp này, một phần tử có cùng kích thước với một con trỏ tới cùng một phần tử, miễn là có 2 phần tử trở lên, mảng phải lớn hơn địa chỉ của phần tử đầu tiên.
vây

53

Chương trình này in 1bằng C ++ và 0bằng C:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int d = (int)(abs(0.6) + 0.5);
    printf("%d", d);
    return 0;
}

Điều này xảy ra vì có double abs(double)quá tải trong C ++, do đó, abs(0.6)trả về 0.6trong khi ở C, nó trả về 0vì chuyển đổi hai chiều thành ẩn trước khi gọi int abs(int). Trong C, bạn phải sử dụng fabsđể làm việc với double.


5
đã phải gỡ lỗi mã của người khác với vấn đề đó. Ôi làm thế nào tôi yêu điều đó. Dù sao chương trình của bạn cũng in 0 trong C ++. C ++ phải sử dụng tiêu đề "cmath", xem so sánh lần đầu tiên returnin 0 ideone.com/0tQB2G Lần thứ hai trả về 1 ideone.com/SLeANo
CoffeDeveloper

Vui mừng / xin lỗi khi biết rằng tôi không phải là người duy nhất tìm thấy sự khác biệt này thông qua việc gỡ lỗi. Chỉ được thử nghiệm trong VS2013, một tệp trống chỉ có tệp có nội dung này sẽ xuất 1 nếu phần mở rộng là .cpp và 0 nếu phần mở rộng là .c. Có vẻ như <math.h> được đưa vào gián tiếp trong VS.
Pavel Chikulaev

Và có vẻ như trong VS C ++, <math.h> bao gồm các công cụ C ++ vào không gian tên toàn cầu, trong khi đối với GCC thì không. Không chắc chắn đó là hành vi tiêu chuẩn tuy nhiên.
Pavel Chikulaev

2
Mẫu mã cụ thể này phụ thuộc vào việc triển khai: stdlib.hchỉ định nghĩa abs(int)abs(long); phiên bản abs(double)được khai báo bởi math.h. Vì vậy, chương trình này vẫn có thể gọi abs(int)phiên bản. Đó là một chi tiết thực hiện cho dù stdlib.hcũng có nguyên nhân math.hđược đưa vào. (Tôi nghĩ rằng nó sẽ là một lỗi nếu abs(double)được gọi, nhưng các aspec khác math.hkhông được bao gồm).
MM

1
Một vấn đề thứ yếu là mặc dù tiêu chuẩn C ++ dường như nói rằng bao <math.h>gồm cả việc quá tải bổ sung; trong thực tế, nó chỉ ra rằng tất cả các trình biên dịch chính không bao gồm các quá tải đó trừ khi <cmath>sử dụng biểu mẫu .
MM

38
#include <stdio.h>

int main(void)
{
    printf("%d\n", (int)sizeof('a'));
    return 0;
}

Trong C, phần này in bất cứ giá trị nào sizeof(int)trên hệ thống hiện tại, thường là 4trong hầu hết các hệ thống được sử dụng phổ biến hiện nay.

Trong C ++, điều này phải in 1.


3
Vâng, tôi thực sự quen thuộc với thủ thuật này, vì 'c' là một số nguyên trong C và một char trong C ++, nhưng vẫn rất tốt để có nó được liệt kê ở đây.
Sean

9
Điều đó sẽ tạo ra một câu hỏi phỏng vấn thú vị - đặc biệt đối với những người đưa chuyên gia c / c ++ vào CV của họ
Martin Beckett

2
Mặc dù vậy. Toàn bộ mục đích của sizeof là vì vậy bạn không cần biết chính xác loại lớn như thế nào.
Dana the Sane

13
Trong C, giá trị được thực hiện được xác định và 1 là một khả năng. (Trong C ++, nó phải in 1 như đã nêu.)
Lập trình viên Windows

3
Trên thực tế, nó có hành vi không xác định trong cả hai trường hợp. %dkhông phải là định dạng đúng định dạng cho size_t.
R .. GitHub DỪNG GIÚP ICE

37

Một sizeofcái bẫy khác : biểu thức boolean.

#include <stdio.h>
int main() {
    printf("%d\n", (int)sizeof !0);
}

Nó bằng với sizeof(int)C, bởi vì biểu thức là loại int, nhưng thường là 1 trong C ++ (mặc dù không bắt buộc phải có). Trong thực tế, chúng hầu như luôn luôn khác nhau.


6
Một !nên là đủ cho a bool.
Alexey Frunze

4
!! là toán tử chuyển đổi int thành boolean :)
EvilTeach

1
sizeof(0)nằm 4trong cả C và C ++ vì 0là một giá trị nguyên. sizeof(!0)4trong C và 1trong C ++. Logic KHÔNG hoạt động trên toán hạng loại bool. Nếu giá trị int là 0nó được chuyển đổi hoàn toàn thành false(một giá trị bool), thì nó được lật, dẫn đến true. Cả hai truefalselà giá trị bool trong C ++ và sizeof(bool)1. Tuy nhiên, trong C !0ước tính 1, đó là một giá trị của kiểu int. Ngôn ngữ lập trình C không có kiểu dữ liệu bool theo mặc định.
Galaxy

26

Ngôn ngữ lập trình C ++ (Ấn bản thứ 3) đưa ra ba ví dụ:

  1. sizeof ('a'), như @Adam Rosenfield đã đề cập;

  2. // ý kiến ​​đang được sử dụng để tạo mã ẩn:

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
  3. Cấu trúc, vv ẩn các công cụ trong phạm vi ra, như trong ví dụ của bạn.


25

Một hạt dẻ cũ phụ thuộc vào trình biên dịch C, không nhận ra các nhận xét cuối dòng C ++ ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...

21

Một số khác được liệt kê theo Tiêu chuẩn C ++:

#include <stdio.h>

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}

Vì vậy, bạn nhận được sự khác biệt đệm?
v.oddou

ah xin lỗi tôi đã nhận nó, có một cái khác xở trên cùng. Tôi nghĩ bạn nói "mảng a".
v.oddou

20

Các hàm nội tuyến trong C mặc định cho phạm vi bên ngoài trong khi các hàm trong C ++ thì không.

Biên dịch hai tệp sau đây với nhau sẽ in "Tôi là nội tuyến" trong trường hợp GNU C nhưng không có gì cho C ++.

Tập tin 1

#include <stdio.h>

struct fun{};

int main()
{
    fun();  // In C, this calls the inline function from file 2 where as in C++
            // this would create a variable of struct fun
    return 0;
}

Tập tin 2

#include <stdio.h>
inline void fun(void)
{
    printf("I am inline\n");
} 

Ngoài ra, C ++ hoàn toàn đối xử với bất kỳ consttoàn cầu nào statictrừ khi nó được tuyên bố rõ ràng extern, không giống như C trong đó externlà mặc định.


Tôi thực sự không nghĩ như vậy. Có lẽ bạn đã bỏ lỡ điểm. Đây không phải là về định nghĩa của struct st mà chỉ được sử dụng để làm cho mã c ++ hợp lệ. Vấn đề là nó làm nổi bật hành vi khác nhau của các hàm nội tuyến trong c vs c ++. Áp dụng tương tự cho bên ngoài. Không ai trong số này được thảo luận trong bất kỳ giải pháp.
fkl

2
Hành vi khác nhau của các chức năng nội tuyến và externđiều đó được thể hiện ở đây là gì?
Seth Carnegie

Nó được viết khá rõ ràng. "Các hàm nội tuyến trong c mặc định cho phạm vi bên ngoài trong đó các hàm trong c ++ không phải là (mã cho thấy điều đó). C ++ cũng coi tất cả các const toàn cầu là phạm vi tệp trừ khi được khai báo rõ ràng bên ngoài, không giống như C trong đó bên ngoài là mặc định. ví dụ có thể được tạo ra cho điều đó ". Tôi hoang mang - Có phải là không hiểu?
fkl

12
@fayyazkl Hành vi được hiển thị chỉ vì sự khác biệt của tra cứu ( struct funvs fn) và không có gì để làm cho dù chức năng là nội tuyến. Kết quả là giống hệt nhau nếu bạn loại bỏ inlinevòng loại.
Alex B

3
Trong ISO C, chương trình này không được định hình: inlinekhông được thêm vào cho đến C99, nhưng trong C99 fun()có thể không được gọi nếu không có nguyên mẫu trong phạm vi. Vì vậy, tôi cho rằng câu trả lời này chỉ áp dụng cho GNU C.
MM

16
struct abort
{
    int x;
};

int main()
{
    abort();
    return 0;
}

Trả về với mã thoát là 0 trong C ++ hoặc 3 trong C.

Thủ thuật này có thể được sử dụng để làm một điều gì đó thú vị hơn, nhưng tôi không thể nghĩ ra một cách tốt để tạo ra một hàm tạo có thể chấp nhận được với C. Tôi đã thử tạo một ví dụ nhàm chán tương tự với hàm tạo sao chép, điều đó sẽ cho phép một đối số được thông qua, mặc dù trong một thời trang không di động:

struct exit
{
    int x;
};

int main()
{
    struct exit code;
    code.x=1;

    exit(code);

    return 0;
}

Tuy nhiên, VC ++ 2005 đã từ chối biên dịch rằng trong chế độ C ++, phàn nàn về cách "mã thoát" được xác định lại. (Tôi nghĩ rằng đây là một lỗi trình biên dịch, trừ khi tôi đột nhiên quên cách lập trình.) Nó đã thoát với mã thoát quy trình là 1 khi được biên dịch thành C mặc dù.


Ví dụ thứ hai của bạn bằng cách sử dụng exit, không biên dịch trên gcc hoặc g ++, thật không may. Đó là một ý tưởng tốt, mặc dù.
Sean

1
exit(code)là một tuyên bố hợp lệ của một biến codeloại exit, rõ ràng. (Xem "hầu hết phân tích cú pháp", đây là một vấn đề khác nhau nhưng tương tự).
dùng253751

16
#include <stdio.h>

struct A {
    double a[32];
};

int main() {
    struct B {
        struct A {
            short a, b;
        } a;
    };
    printf("%d\n", sizeof(struct A));
    return 0;
}

Chương trình này in 128( 32 * sizeof(double)) khi được biên dịch bằng trình biên dịch C ++ và 4khi được biên dịch bằng trình biên dịch C.

Điều này là do C không có khái niệm về độ phân giải phạm vi. Trong cấu trúc C có trong các cấu trúc khác được đưa vào phạm vi của cấu trúc bên ngoài.


Điều này thật thú vị! (Tôi nghĩ bạn có ý 32*sizeof(double)chứ không phải 32 mặc dù :))
user1354557 18/2/2016

3
lưu ý rằng bạn đang nhận được UB bằng cách in size_tbằng%d
phuclv

7

Đừng quên sự khác biệt giữa các không gian tên toàn cầu C và C ++. Giả sử bạn có một foo.cpp

#include <cstdio>

void foo(int r)
{
  printf("I am C++\n");
}

và một foo2.c

#include <stdio.h>

void foo(int r)
{
  printf("I am C\n");
}

Bây giờ giả sử bạn có một main.cmain.cpp , cả hai đều trông như thế này:

extern void foo(int);

int main(void)
{
  foo(1);
  return 0;
}

Khi được biên dịch thành C ++, nó sẽ sử dụng ký hiệu trong không gian tên toàn cầu C ++; Trong C, nó sẽ sử dụng một C:

$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test 
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test 
I am C

Bạn có nghĩa là các đặc điểm kỹ thuật liên kết?
dùng541686

tên xáo trộn. Tên C ++ có tiền tố và hậu tố trong khi C không
CoffeDeveloper

Tên xáo trộn không phải là một phần của đặc tả C ++. Có bị cấm trong C?
bầu trời

5
Đây là hành vi không xác định (nhiều định nghĩa của foo). Không có "không gian tên toàn cầu" riêng biệt.
MM

4
int main(void) {
    const int dim = 5; 
    int array[dim];
}

Điều này khá đặc biệt ở chỗ nó hợp lệ trong C ++ và C99, C11 và C17 (mặc dù tùy chọn trong C11, C17); nhưng không hợp lệ trong C89.

Trong C99 +, nó tạo ra một mảng có độ dài thay đổi, có đặc thù riêng của nó so với các mảng thông thường, vì nó có kiểu thời gian chạy thay vì kiểu thời gian biên dịch và sizeof arraykhông phải là biểu thức hằng số nguyên trong C. Trong C ++, kiểu này hoàn toàn tĩnh.


Nếu bạn cố gắng thêm một trình khởi tạo ở đây:

int main(void) {
    const int dim = 5; 
    int array[dim] = {0};
}

là C ++ hợp lệ nhưng không phải C, vì các mảngđộ dài thay đổi không thể có bộ khởi tạo.


0

Điều này liên quan đến giá trị và giá trị trong C và C ++.

Trong ngôn ngữ lập trình C, cả toán tử tăng trước và toán tử tăng sau đều trả về giá trị, không phải giá trị. Điều này có nghĩa là chúng không thể ở bên trái của =toán tử gán. Cả hai câu lệnh này sẽ đưa ra lỗi trình biên dịch trong C:

int a = 5;
a++ = 2;  /* error: lvalue required as left operand of assignment */
++a = 2;  /* error: lvalue required as left operand of assignment */

Tuy nhiên, trong C ++, toán tử tăng trước trả về một giá trị , trong khi toán tử tăng sau trả về một giá trị . Nó có nghĩa là một biểu thức với toán tử tăng trước có thể được đặt ở phía bên trái của =toán tử gán!

int a = 5;
a++ = 2;  // error: lvalue required as left operand of assignment
++a = 2;  // No error: a gets assigned to 2!

Bây giờ tại sao lại như vậy? Gia tăng sau tăng biến, và nó trả về biến như trước khi tăng tăng xảy ra. Đây thực sự chỉ là một giá trị. Giá trị trước đây của biến a được sao chép vào một thanh ghi dưới dạng tạm thời và sau đó a được tăng lên. Nhưng giá trị trước đây của a được trả về bởi biểu thức, nó là một giá trị. Nó không còn đại diện cho nội dung hiện tại của biến.

Gia số trước đầu tiên tăng biến, và sau đó nó trả về biến như đã tăng sau khi gia tăng xảy ra. Trong trường hợp này, chúng ta không cần lưu trữ giá trị cũ của biến vào một thanh ghi tạm thời. Chúng tôi chỉ lấy giá trị mới của biến sau khi nó đã được tăng lên. Vì vậy, phần tăng trước trả về một giá trị, nó trả về biến a chính nó. Chúng ta có thể sử dụng gán giá trị này cho một cái gì đó khác, nó giống như tuyên bố sau đây. Đây là một chuyển đổi ngầm định của lvalue thành rvalue.

int x = a;
int x = ++a;

Vì mức tăng trước trả về một giá trị, chúng ta cũng có thể gán một cái gì đó cho nó. Hai tuyên bố sau là giống hệt nhau. Trong bài tập thứ hai, đầu tiên a được tăng lên, sau đó giá trị mới của nó được ghi đè bằng 2.

int a;
a = 2;
++a = 2;  // Valid in C++.

3
Không có "hợp lệ trong C" ở đây.
o11c

0

Các cấu trúc trống có kích thước 0 trong C và 1 trong C ++:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}

1
Không, sự khác biệt là C không có cấu trúc trống, ngoại trừ phần mở rộng của trình biên dịch, tức là mã này không khớp "có giá trị trong cả C và C ++"
Antti Haapala
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.