在同一个文件中使用extern

时间:2018-06-05 11:22:07

标签: c linker extern

我对同一文件中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;
}

案例2:

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;
}

4 个答案:

答案 0 :(得分:6)

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

在第二种情况下,您有一个全局a,它位于此或在您使用本地a覆盖的另一个模块(c文件/编译单元)中。它将打印20

在第三种情况下,您使用全局a覆盖的本地a显然在任何编译单元中都不存在,因此链接器错误。

答案 1 :(得分:4)

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

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

  

对于使用存储类说明符extern声明的标识符   在可以看到该标识符的先前声明的范围内,   如果先前的声明指定内部或外部链接,   后来声明中标识符的链接是   与先前声明中指定的联系相同。

因此,在前两个案例中,内部extern int a;有一个事先声明 - 在您的第一个案例中为全局int a;,在您的第二个案例中为extern int a; - 因此{{1声明是指全局。

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

  

如果没有先前的声明可见,或者如果之前的声明   声明指定没有链接,然后标识符具有外部链接

此外,第6段指出:

  

以下标识符没有链接:声明为除。之外的任何标识符   对象或功能;声明为函数参数的标识符; 块范围   没有存储类说明符声明的对象的标识符   extern int a;

因此,第三种情况下的声明是指extern

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

6.9.2外部对象定义,第2段规定:

  

具有文件范围的对象的标识符声明,没有初始值设定项,以及   没有存储类说明符或存储类说明符   int a;,构成一个   暂定的定义。如果翻译单元包含一个或多个临时定义   然后,标识符和转换单元不包含该标识符的外部定义   行为就像翻译单元包含该文件范围声明一样   标识符,具有复制类型,如翻译单元的末尾,带有初始化程序   等于0。

因此,第三个案例的块范围static声明不符合暂定定义。

答案 2 :(得分:1)

案例1:

extern int a ;声明声明了一个在其他位置定义的int a变量,因此隐藏了此处声明的a变量:int a = 20 ;。然后,链接器正在查找全局变量a,并且由于int a = 10 ;声明而在同一文件中找到它。输出为10

案例2:

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

案例3:

这与情况1类似。它确实正确编译,但没有链接,因为extern int a ;声明了一个int a变量,可能在其他地方定义,但事实并非如此,因为你注释掉了int a = 10 ;声明。

答案 3 :(得分:1)

案例1: - 在第一个代码块中,extern int a;表示此处声明了变量a,但告诉链接器在{{{}}上找到a的定义1}}不在main()。如果链接器能够在main()之上找到a的定义,那么它将链接否则导致链接器错误。在您的情况下,链接器将main()作为a

案例2: - 在这种情况下,上面全局声明的10告诉链接器extern int a;的定义可能位于a的其他文件或同一文件中{1}}功能。这里main()表示,如果您需要,将在中定义一个带有静态持续时间和外部链接extern int a;全局变量)的定义文件在另一个文件中。该声明被a中的定义隐藏,因此main()使用printf()。 这个

local variable

考虑本地声明的printf("A value: %d\n",a);。所以它会打印a

案例3: - 在这种情况下声明

20

导致链接器错误,因为链接器将尝试在extern int a; // Why now I get a linking error 之上找到a的定义,并且它不在那里(您评论过),因此它会导致链接器错误