如果我有这样的外部变量:
int a;
是正确的,声明等于:
extern int a = 0;
而不等于:
extern int;
是否与本地变量相同,其中写的内容如下:
int local;
等于:
auto int local;
在这两种情况下,编译器是否默认设置了说明符extern
或auto
?
答案 0 :(得分:4)
extern int a
在文件范围声明变量但不定义它。这样的声明基本上表示该变量可以在另一个编译单元中找到,并且链接器的工作是在合并各个目标文件时解析其地址。在这种情况下省略extern
将定义当前单位中的变量,并将其初始值设置为0
(暂定定义)。除非使用extern
,否则这样定义的变量将具有外部链接(无论static
被省略)。
extern int a = 0
是定义,extern
没有意义,因为您告诉编译器在这里初始化变量。在这种情况下,可以安全地省略extern
。
是否与auto
相同?在某种程度上,extern
和auto
都是存储类说明符,是的。但是,自动变量(无论是否使用该关键字定义)不会隐式初始化。使用未初始化的auto
变量是未定义的行为。此外,声明函数中的变量是不可能的,因此这里的混淆要少得多。
答案 1 :(得分:4)
关联和外部定义的规则有点奇怪,部分原因是出于历史原因(参见例如this C89理由)。对象的规则(它们对于函数声明是不同的)是:
在文件范围:
auto
和register
是不允许的,需要诊断 1)。static
表示内部联系 2),声明是(暂定)定义 3)。extern
表示已声明的链接,如果没有声明,则外部链接 4)。暂定定义意味着,对象将在同一个翻译单元中定义,如果没有明确的定义,则假定0
。 8)多个显式定义是约束违规用于内部联系的标识符;对于具有外部链接的标识符,行为未定义(Gcc中止编译)。 9)
前两个例子主要是,但不完全等同。
int a;
a
有外部联系。宣言是一个暂定的定义;如果没有显式初始化,则将其初始化为0.如果存在另一个声明static int a;
,则行为将是未定义的。
extern int a = 0;
另一方面,只有当外部声明已经可见或者没有可见时,才会声明a
具有外部链接。如果之后是a
的静态声明,则行为未定义;如果这之前是一个,则链接将是内部的。此声明还将a
初始化为0,不允许在翻译单元中显示其他明确定义。
extern int a;
(我假设extern int a;
而不是extern int;
。如果你的确意味着后者:那是违反约束条款。)
这是一个(外部的,如果没有其他声明可见)声明没有定义。通常,定义出现在另一个翻译单元中。如果标识符用于评估它的表达式,它必须出现在某处。
在块范围内:
extern
表示与文件范围相同,但没有暂定定义。不允许初始化。 10) static
表示没有链接(但是静态存储持续时间)。 11)如果没有初始化,则将其初始化为0(一次,在程序启动时)。 12) auto
或者没有意味着没有联系。如果没有初始化 13),变量的值是不确定的,读取这样的值是不确定的(不完全,但实际上)。register
与auto
相同,但取其地址是违反约束的。因此,最后两个例子是等效的。
此处未提及的两个存储类说明符是typedef
和(自C11开始)_Thread_local
。 15)
参考C11(n1570):
1) 6.9 p2。 2) 6.2.2 p3。 3) 6.9.2 p2。 4) 6.2.2 p4。 5) 6.2.2 p5。 6) 6.9.2 p2。 7) 6.2.2 p7 8) 6.9.2 p2。 9) 6.9 p3和p5。 10) 6.2.2 p4和6.7.9 p5。 11) 6.2.2 p6。 12)和 13) 6.7.9 p10。 14)6.7 p3。 15)参见6.7.1。
答案 2 :(得分:2)
在此文件中实例化全局变量:
int a; // instantiation
int a = 0; // instantiation and initialization
编译期间将解析全局变量的地址。
告诉编译器全局变量在另一个文件中实例化:
extern int a;
全局变量的地址将在链接期间解析。
使用extern int a = 0
,您强制a
的实例化,从而使extern
无用。
答案 3 :(得分:0)
int a;和extern int a = 0;是平等的。当我们初始化一个extern变量时,也会为该变量分配内存,即也会出现与int a;类似的定义。 有关extern的更多信息,请参阅http://www.geeksforgeeks.org/understanding-extern-keyword-in-c。