在C和C ++中有效的代码在每种语言中编译时会产生不同的行为吗?

C和C ++有很多不同之处,并不是所有有效的C代码都是有效的C ++代码。
(“有效的”是指定义行为的标准代码,即不是特定于实现的/未定义的/等)。

在每种语言中使用标准编译器进行编译时,是否有任何一种C和C ++中有效的代码会产生不同的行为?

为了使之成为一个合理/有用的比较(我试图学习一些实际有用的东西,不要试图在问题中find明显的漏洞),让我们假设:

  • 没有任何预处理器相关的(这意味着不用#ifdef __cplusplus ,编译指示等等)
  • 任何实现定义在两种语言都是相同的(例如数字限制等)
  • 我们比较每个标准的合理的最新版本(例如,C ++ 98和C90或更高版本)
    如果版本很重要,那么请提及每个版本产生不同的行为。

在C和C ++中有效的以下内容(很有可能)会导致C和C ++中的不同值:

 int i = sizeof('a'); 

在C / C ++中查看字符的大小('a')来解释差异。

更新:从这篇文章的另一个:

 #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; } 

下面是一个利用C和C ++中的函数调用和对象声明之间的区别的例子,以及C90允许调用未声明的函数的事实:

 #include <stdio.h> struct f { int x; }; int main() { f(); } int f() { return printf("hello"); } 

在C ++中,这将不会打印任何东西,因为临时的f被创build和销毁,但是在C90中它会打印出hello因为函数可以被调用而不被声明。

如果你想知道f被使用了两次,那么C和C ++标准明确地允许这样做,并且使一个对象你必须说struct f来消除你想要的结构,或者如果你想要这个结构。

对于C ++和C90,至less有一种方法可以获得不同于实现定义的行为。 C90没有单行注释。 稍加小心,我们可以用C90和C ++来创build一个完全不同结果的expression式。

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

在C ++中,从//到结尾的所有内容都是注释,所以这可以看作是:

 int a = 10 + 3; 

由于C90没有单行注释,所以只有/* comment */是注释。 第一个和第二2都是初始化的一部分,所以它出现在:

 int a = 10 / 2 + 3; 

所以,一个正确的C ++编译器会给出13个,但是是一个正确的C编译器8.当然,我只是在这里select了任意数字 – 你可以使用其他数字。

C90与C ++ 11( intdouble ):

 #include <stdio.h> int main() { auto j = 1.5; printf("%d", (int)sizeof(j)); return 0; } 

在C中auto表示局部variables。 在C90中,可以省略variables或函数types。 它默认为int 。 在C ++ 11中, auto表示完全不同的东西,它告诉编译器从用于初始化variables的值中推断variables的types。

另一个我还没有提到的例子,这个例子强调了一个预处理器的区别:

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

这在C中输出“false”,在C ++中输出“true” – 在C中,任何未定义的macros的值都为0.在C ++中,有1个exception:“true”的值为1。

按照C ++ 11标准:

一个。 逗号运算符在C中执行左值到右值的转换,但不是C ++:

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

在C ++中,这个expression式的值将是100,在C中,这将是sizeof(char*)

在C ++中,枚举types是枚举types。 在C中,枚举types是int。

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

这意味着sizeof(int)可能不等于sizeof(E)

C。 在C ++中,用空params列表声明的函数不带任何参数。 在C空params列表意味着函数参数的数量和types是未知的。

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

该程序在C ++中打印1在C中打印0

 #include <stdio.h> #include <stdlib.h> int main(void) { int d = (int)(abs(0.6) + 0.5); printf("%d", d); return 0; } 

发生这种情况是因为在C ++中有double abs(double)重载,所以abs(0.6)返回0.6而在C中它返回0因为在调用int abs(int)之前隐式的double-to-int转换。 在C中,你必须使用fabs来处理double

另一个sizeof陷阱:布尔expression式。

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

它等于C中的sizeof(int) ,因为expression式的types是int ,但在C ++中通常是1(尽pipe它不是必须的)。 实际上他们几乎总是不同的。

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

在C中,这会打印当前系统上sizeof(int)的值,在当今大多数系统中通常是4

在C ++中,这必须打印1。

C ++编程语言(第三版)给出了三个例子:

  1. sizeof('a'),就像@Adam Rosenfield提到的那样;

  2. //用于创build隐藏代码的注释:

 int f(int a, int b) { return a //* blah */ b ; } 

3)结构等隐藏在范围外的东西,如你的例子。

一个依赖于C编译器的旧栗子,不能识别C ++行尾注释…

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

另一个由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)); } 

C中的内联函数默认为外部作用域,而C ++中的内联函数不包含这些作用域。

把下面两个文件编译在一起,在GNU C的情况下会打印出“我是内联的”,但是对于C ++来说则不是。

文件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; } 

文件2

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

另外,C ++将任何const全局隐式地视为static除非它明确地声明为extern ,而不像extern是默认的C。

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

在C ++中返回退出代码为0,或者在C中退出3

这个技巧可能可以用来做更有趣的事情,但是我想不出创build一个对C来说可口的构造函数的好方法。我试着用copy构造函数做一个类似无聊的例子,它会让参数虽然是非常不便携的方式,

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

VC ++ 2005拒绝在C ++模式下编译,但是抱怨“退出代码”是如何重新定义的。 (我认为这是一个编译器错误,除非我突然忘记了如何编程)。当编译为C时,退出的进程退出代码为1。

 #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; } 

该程序使用C ++编译器编译时打印12832 * sizeof(double) ),使用C编译器编译时打印4

这是因为C没有范围parsing的概念。 在其他结构中包含的C结构被放入外部结构的范围。

不要忘记C和C ++全局名称空间的区别。 假设你有一个foo.cpp

 #include <cstdio> void foo(int r) { printf("I am C++\n"); } 

和一个foo2.c

 #include <stdio.h> void foo(int r) { printf("I am C\n"); } 

现在假设你有一个main.cmain.cpp ,它们都是这样的:

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

当编译为C ++时,它将使用C ++全局名称空间中的符号; 在C中它将使用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