我对同一文件中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;
}
在第一种情况下,你有一个全局a
,你用本地(自动) a
覆盖你再次覆盖全局a
(extern只能引用某些模块中的全局变量)。 它将打印10
。
在第二种情况下,你有一个全局a
,它存在于你或用本地a
覆盖的另一个模块(c文件/编译单元)中。 它将打印20
。
在第三种情况下,您有一个本地a
,您使用全局a
覆盖,显然在任何编译单元中都不存在,因此链接器错误。
(请注意,对问题中代码的编辑似乎使得此答案的某些部分不再完全正确。)
按6.2.2标识符的链接 , C标准第4段:
对于在该标识符的先前声明可见的范围内使用存储类说明符
extern
声明的标识符,如果先前声明指定内部或外部链接, 则后面声明中标识符的链接与链接相同在先前的声明中指明。
所以,在前两个案例中,内部extern int a;
有一个事先声明 - 全球int a;
在你的第一个案件或extern int a;
在你的第二种情况下 - 所以extern int a;
声明是指全球。
对于第三种情况,第4款的其余部分是相关的:
如果没有先前声明可见,或者先前声明未指定链接,则标识符具有外部链接 。
另外,第6段指出:
以下标识符没有链接:声明为对象或函数以外的任何标识符; 声明为函数参数的标识符; 没有存储类说明符
extern
声明的对象的块作用域标识符。
所以你的第三个案例中的声明是指一个extern int a;
但是,没有实际的int a;
任何地方定义 而且因为extern int a;
在你的第三个例子中出现在块范围内,并且没有int a;
实际定义int a;
对象在其他地方,您的程序无法链接。
根据6.9.2外部对象定义 ,第2段规定:
具有没有初始化程序的文件范围且没有存储类说明符或存储类说明符为
static
的对象的标识符声明构成暂定定义。 如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。
所以块范围extern int a;
你的第三个案件的声明不符合暂定的定义。
情况1:
extern int a ;
声明将一个int a
声明为int a
在别处定义int a
变量,从而遮蔽在a
声明a
变量: int a = 20 ;
。 然后链接器正在查找全局变量a
并在同一个文件中找到它,因为int a = 10 ;
宣言。 输出为10
。
案例2:
这里的extern int a ;
声明无效。 在main
里面声明的局部变量int a = 20 ;
使用,因此输出为20
。
案例3:
这与情况1类似。它确实编译正确,但是因为extern int a ;
而没有链接extern int a ;
声明一个int a
可能在其他地方定义int a
变量,但事实并非如此,因为你注释掉了int a = 10 ;
宣言。
案例1: -在第一个代码块extern int a;
表明变量a
是在这里声明,但告诉链接找到的定义a
以上main()
不是在main()
。 如果连接是能够找到的定义a
以上main()
那么它将链接,否则会导致连接错误。 在你的情况下连接器将a
为10
。
案例2: -在这种情况下,全局声明的extern int a;
告诉链接器a
定义可能在其他文件中或在main()
函数的同一文件中。 这里extern int a;
是说,如果你需要它,就会有一个静态的持续时间和外部链接 (定义a
全局变量)无论是在本文件 或其他文件中定义。 该声明被main()
的定义隐藏,因此printf()
使用local variable
。 这个
printf("A value: %d\\n",a);
考虑在当地宣布a
。 所以打印20
。
案例3: -在这种情况下声明
extern int a; // Why now I get a linking error
造成连接错误,因为连接器将试图找到定义a
以上main()
和它的不存在(您的评论),所以它在链接器错误的结果。