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