GCC多次声明全局变量时没有警告或错误

use*_*269 4 c gcc

假设以下代码:

AC:

#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;
}
Run Code Online (Sandbox Code Playgroud)

和bc:

int a;

int func()
{
a = 9;
return a;
}
Run Code Online (Sandbox Code Playgroud)

使用g++ a.c b.c -Wall -O0它编译时会产生链接错误,如预期的那样.但是,调用gcc a.c b.c -Wall -O0它时不会产生警告而且没有错误!

输出a is 9, a2 is 9顺便说一下.

gcc版本5.4.0 20160609(Ubuntu 5.4.0-6ubuntu1~16.04.4)

GCC为什么允许这样做?我对这种行为感到惊讶.如果在声明时初始化变量,那么链接也将失败并使用GCC.

usr*_*usr 5

使用g++ a.c b.c -Wall -O0它编译时会产生链接错误,如预期的那样.但是,调用gcc a.c b.c -Wall -O0它时不会产生警告而且没有错误!

在你的代码中a暂定定义(在当前翻译单元的末尾成为一个完整的定义),它在C中有效.但是,还有另一个这样的暂定定义,它b.c从另一个翻译单元变成一个完整的定义- 两者都提供了程序中的外部定义a.换句话说,a.c并且b.c它们本身很好但是当它们组合在一起时(无论是直接编译还是将它们编译成单独的模块然后通过链接它们来生成可执行文件)都是无效的.这是未定义的行为:

C11,6.9/5:

外部定义是外部声明,它也是函数(内联定义除外)或对象的定义.如果在表达式中使用通过外部链接声明的标识符(除了作为sizeof或_Alignof运算符的操作数的一部分,其结果是整数常量),则整个程序中的某个地方应该只有一个标识符的外部定义; 否则,不得超过一个

然而,这通常被gcc作为扩展支持.这就是为什么当你调用gcc它时编译好C代码.严格(标准),这是C中的无效代码.

当你调用g++它作为C++代码编译时,它会失败,因为C++没有暂定的定义.它在C++中无效.因此,g++出错了.请参阅C++中的一个定义规则.