为什么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地址。 地址也一样。

现在我有以下问题:

  1. 即使没有使用extern gcc自动编译和链接吗? 这里显然是gcc内部这样做,因为我正在编译这两个文件。
  2. 这种带有/不带extern关键字的行为是否依赖于编译器?

此代码是未定义的行为,无需诊断。 Test1.cTest2.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实现了这个扩展,那么它将解释你观察到的行为。 据推测,该引文中的“多个初始化”不计算为暂定定义生成的隐式初始化程序。