我对同一文件中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;
}
答案 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
的定义,并且它不在那里(您评论过),因此它会导致链接器错误。