为什么GCC编译并链接两个文件,即使没有使用’extern’?
以下是用两个单独的文件Test1.c和Test2.c编写的两个独立代码。 我没有在任何文件中使用extern
关键字。
//Test1.c #include int a = 1; int main() { printf("test1 - a val = %d\n",a); fn(); printf("After Return : %d",a); } //Test2.c #include int a; int fn() { printf("test2 - a val = %d\n",a); a++; }
我用gcc编译了这段代码:
gcc Test1.c Test2.c
它生成以下输出:
test1 - a val = 1 test2 - a val = 1
我尝试在两个代码中打印变量a
地址。 地址也一样。
现在我有以下问题:
- 即使没有使用
extern
gcc
自动编译和链接吗? 这里显然是gcc
内部这样做,因为我正在编译这两个文件。 - 这种带有/不带
extern
关键字的行为是否依赖于编译器?
此代码是未定义的行为,无需诊断。 Test1.c
和Test2.c
都定义了a
带有外部链接的对象a
,它违反了C11 6.9 / 5:
如果在表达式中使用通过外部链接声明的标识符(除了作为sizeof或_Alignof运算符的操作数的一部分,其结果是整数常量),则整个程序中的某个地方应该只有一个标识符的外部定义; 否则,不得超过一个。
注意:“外部定义”表示文件范围的定义。 (C11 6.9 / 4,6.9 / 5)。 其他一些注释/答案将“外部定义”与“使用外部链接定义对象”或“使用extern
关键字定义”混淆。 static int x = 5;
在文件范围是一个外部定义。
正如Jonathan Leffler在评论中所提到的,这个特定的结果可能是故意的GCC扩展。 从C11附件J.5.11“共同扩展”:
对象的标识符可能有多个外部定义,有或没有明确使用关键字extern; 如果定义不一致,或者初始化了多个,则行为未定义。
如果gcc实现了这个扩展,那么它将解释你观察到的行为。 据推测,该引文中的“多个初始化”不计算为暂定定义生成的隐式初始化程序。