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

时间:2017-02-15 23:06:45

标签: c gcc

假设以下代码:

交流转换器:

#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 is 9, a2 is 9

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

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

1 个答案:

答案 0 :(得分:5)

  

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

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

C11, 6.9/5

  

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

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

当您调用g++将其编译为C ++代码时,它会失败,因为C ++没有暂定定义。它在C ++中无效。因此,g++出错了。请参阅C ++中的One Definition Rule