在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( int
与double
):
#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 ++编程语言(第三版)给出了三个例子:
-
sizeof('a'),就像@Adam Rosenfield提到的那样;
-
//
用于创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 ++编译器编译时打印128
( 32 * 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.c和main.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