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

hvvq6cgz  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(227)

此问题在此处已有答案

Tentative definitions in C and linking(3个答案)
五年前就关门了。
假设以下代码:

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

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

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

sg24os4d

sg24os4d1#

当用g++ a.c b.c -Wall -O0编译时,它会产生一个链接错误,正如预期的那样。但是,当调用gcc a.c b.c -Wall -O0时,它不会产生警告和错误!
在您的代码中,a有一个在C中有效的 * 临时定义 *(在当前翻译单元的末尾变为 * 完整 * 定义)。
但是,还有另一个这样的暂定定义,它从另一个翻译单元变成了b.c中的完整定义--这两个翻译单元都为程序中的a提供了外部定义。换句话说,a.cb.c本身就很好,但如果将它们组合在一起或编译在一起,则无效(要么直接执行,要么将它们编译成单独的模块,然后通过链接它们来生成可执行文件)。这是 *undefined behavior *:
C11、6.9/5:
外部定义是一个外部声明,它也是一个函数(而不是内联定义)或对象的定义。如果一个标识符用外部链接声明,并在一个表达式中使用(而不是作为sizeof或_Alignof运算符的操作数的一部分,其结果是一个整型常量),在整个程序中的某个地方应该有一个标识符的外部定义;否则,不应超过一个。161
然而,GCC通常支持这种扩展。这就是为什么当你调用gcc时,它可以像C代码一样编译。严格地说(标准的),这在C中是无效的代码。
当你调用g++将其编译为C代码时,它会失败,因为C没有临时定义。它在C中是无效的。因此,g++会出错。请参见One Definition Rule in C

相关问题