在同一文件中使用 extern

Usage of extern in the same file

我对 extern 在同一文件中的用法感到困惑,如下面的代码所示。第一种情况实际上是在 C 中打印全局变量的解决方案(当存在同名局部变量时),但我无法理解它是如何工作的以及第三种情况如何不起作用。

案例 1:

int a = 10;
int main()
{
    int a = 20;
    {
        extern int a; // Is this telling the linker to use global variable? 
        printf("A value: %d\n", a);
    }
    return 0;
}

案例二:

extern int a; // If in the above case extern was telling linker to use global variable 
              // then how in this local variable is getting referred
int main()
{
    int a = 20;
    {
        printf("A value: %d\n", a);
    }
    return 0;
}

案例 3:

// int a = 10;
int main()
{
    int a = 20;
    {
         extern int a; // Why now I get a linking error
         printf("A value: %d\n", a);
    }
    return 0;
}

案例一:

extern int a ; 声明声明了一个在别处定义的 int a 变量,因此隐藏了此处声明的 a 变量:int a = 20 ;。然后 linker 正在寻找一个全局变量 a 并且由于 int a = 10 ; 声明而在同一个文件中找到它。输出为 10.

案例二:

此处extern int a ; 声明无效。在 main 中,使用了此处声明的局部变量 int a = 20 ;,因此输出为 20.

案例三:

这与案例 1 类似。它编译正确,但不是 link 因为 extern int a ; 声明了一个可能在其他地方定义的 int a 变量,这不是案例,因为您注释掉了 int a = 10 ; 声明。

在第一种情况下,您有一个全局 a,您用本地(自动)a 覆盖,您再次用全局 a 覆盖(外部只能引用某些模块中的全局变量)。它将打印 10.

在第二种情况下,您有一个全局 a,它驻留在您用本地 a 覆盖的这个或另一个模块(c file/compilation 单元)中。它将打印 20.

在第三种情况下,您有一个局部 a,您用全局 a 覆盖了它,而全局 a 显然不存在于您的任何编译单元中,因此出现链接器错误。

案例 1:- 在第一个代码块中 extern int a; 表示变量 a 在这里声明但告诉 linker 找到a 上面的定义 main() 不在 main() 中。如果 linker 能够在 main() 上方找到 a 的定义,那么它将 link 否则会导致 linker 错误。在您的情况下,linker 会将 a 视为 10

情况 2 :- 在这种情况下,上面全局声明的 extern int a; 告诉 linker a 的定义可能在main() 函数中的其他文件或同一文件中。这里extern int a;是说如果你需要的话,会定义一个withstatic duration和外部linkage(a全局变量) 在这个文件另一个文件中定义。该声明被 main() 中的定义隐藏,因此 printf() 使用 local variable。 这个

printf("A value: %d\n",a);

考虑本地声明 a。所以它打印 20.

案例 3 :- 在这种情况下语句

extern int a; // Why now I get a linking error

导致 linker 错误,因为 linker 将尝试在 main() 上方找到 a 的定义,但它不存在(你评论过)所以它导致 link错误.

(请注意,对问题中代码的编辑似乎使该答案的部分内容不再完全正确。)

根据 6.2.2 标识符的链接the C standard 的第 4 段:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration.

因此,在前两种情况下,内部 extern int a; 有一个事先声明 - 第一种情况是全局 int a; ,第二种情况是 extern int a; - 所以 extern int a;声明指的是全局。

对于第三种情况,第 4 段的其余部分是相关的:

If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

此外,第 6 段指出:

The following identifiers have no linkage: an identifier declared to be anything other than an object or a function; an identifier declared to be a function parameter; a block scope identifier for an object declared without the storage-class specifier extern.

所以你第三个案例中的声明指的是 extern int a;

但是,任何地方都没有实际的 int a; 定义。并且由于第三个示例中的 extern int a; 出现在块作用域中,并且其他地方没有 int a; 对象的实际定义,因此您的程序无法 link.

根据 6.9.2 外部对象定义,第 2 段指出:

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

所以你的第三个案例的块范围 extern int a; 声明不符合暂定定义。