为什么GCC会编译和链接两个文件,即使“extern”'未使用?

时间:2017-01-12 06:53:33

标签: c extern

以下是用两个单独的文件Test1.c和Test2.c编写的两个独立代码。我没有在任何文件中使用extern关键字。

//Test1.c
#include <stdio.h>

int a = 1;
int main()
{
    printf("test1 - a val = %d\n",a);
    fn();
    printf("After Return : %d",a);
}

//Test2.c
#include <stdio.h>

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. 即使gcc未使用,extern是否会自动编译和链接?显然gcc内部就是这样,因为我正在编译这两个文件。
  2. 这种带/不带extern关键字的行为是依赖于编译器的吗?

1 个答案:

答案 0 :(得分:3)

此代码是未定义的行为,无需诊断。 Test1.cTest2.c都定义了一个带有外部链接的对象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实现了这个扩展,那么它将解释你观察到的行为。据推测,该引文中“不止一个被初始化”不计算为暂定定义生成的隐式初始化器。