假设如下代码:
文件 a.c
#include <stdio.h>
int a;
int func();
int main(int argc, char **argv) {
a = 7;
int a2 = func();
printf("a is %d, a2 is %d\n", a, a2);
return 0;
}
文件 b.c
int a;
int func()
{
a = 9;
return a;
}
当使用 g++ a.c b.c -Wall -O0
编译时,如预期的那样会产生链接错误。但是,当调用 gcc a.c b.c -Wall -O0
时,它不会产生任何警告或错误!
顺便说一句,输出是a是9,a2是9
。
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
为什么 GCC 允许这样做?
我对这种行为感到惊讶。如果您在声明时初始化变量,则 GCC 的链接也会失败。
When compiled with g++ a.c b.c -Wall -O0
it produces a linking error, as expected. However, when invoking gcc a.c b.c -Wall -O0
it produces no warning and no error!
在您的代码中,a
有一个暂定定义(在当前翻译单元的末尾变成一个完整定义)它是在 C 中有效。
然而,还有另一个这样的暂定定义,它成为来自另一个翻译单元的 b.c
中的完整定义——它们都为您的程序中的 a
提供了外部定义。换句话说,a.c
和 b.c
单独使用没问题,但是当它们组合在一起编译时(您直接编译或将它们编译成单独的模块,然后通过链接它们来制作可执行文件)。这是未定义的行为:
C11, 6.9/5 :
An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.161
然而,这通常作为扩展被 GCC 支持。这就是为什么当您调用 gcc
时,它可以像 C 代码一样很好地编译。严格来说(标准方面),这是 C 中的无效代码。
当您调用 g++
将其编译为 C++ 代码时,它会失败,因为 C++ 没有临时定义。它在 C++ 中无效。因此,g++
出错了。参见 One Definition Rule在 C++ 中。