为什么以下不编译?
...
extern int i;
static int i;
...
但如果顺序颠倒,它编译罚款。
...
static int i;
extern int i;
...
这里发生了什么?
为什么以下不编译?
...
extern int i;
static int i;
...
但如果顺序颠倒,它编译罚款。
...
static int i;
extern int i;
...
这里发生了什么?
当它的宣告讨论的外部或内部联动的复杂性,这是特别如在C ++标准为例进行说明。 这是在第7.1.1.7,它有这个使出:
static int b ; // b has internal linkage
extern int b ; // b still has internal linkage
extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
第3.5.6节讨论如何extern
应该表现在这种情况下。
发生了什么事是这样的: static int i
(在这种情况下)是一个定义,其中static
显示, i
有内在联系。 当extern
后出现static
编译器看到这个符号已经存在,并且接受它已经具有内在联系和进行。 这就是为什么你的第二个例子编译。
该extern
,另一方面是一个声明,它含蓄地指出,符号有外部链接,但实际上并没有创造任何。 由于没有i
在你的第一个例子中,编译器寄存器i
具有外部链接,但是当它到达您的static
发现不兼容的声明,它有内在联系,并给出了一个错误。
换句话说,它是因为声明比定义“更软”。 例如,你可以多次申报同一件事没有错误,但你只能一次定义它。
这是否是在C语言一样,我不知道(但低于netcoder的回答告诉我们,C标准包含相同的要求)。
对于C,引用标准,在C11 6.2.2: 标识符的链接 :
3)如果一个对象或功能的文件范围标识符的声明包含存储类说明
static
,所述标识符具有内部连接。4) 为了与存储类说明中声明的标识符
extern
在一个范围,其中该标识符的先前声明是可见的 ,如果事先声明指定的内部或外部联动, 在后面的声明中的识别符的连接是相同在现有声明中指定的连接 。 如果没有事先声明是可见的,或者如果现有声明指定没有连锁,则标识符具有外部连接。
(重点矿)
这解释了第二个例子中( i
将具有内部链接)。 至于第一个,我敢肯定这是未定义的行为:
7)如,一个翻译单元内,相同的标识符出现与内部和外部连接,该行为是未定义。
......因为extern
标识宣告前内部联动,出现6.2.2 / 4不适。 因此, i
有内部和外部连接,所以它的UB。
如果编译器发出的诊断,以及幸运的,你我猜。 它可能没有错误编译两个,仍然是符合标准的。
在Microsoft Visual Studio,这两个版本的编译就好了。 在GNU C ++中,你得到一个错误。
我不知道该编译器是“正确的”。 无论哪种方式,同时具有线没有太大的意义。
extern int i
意味着整数i
在一些其他模块(对象文件或库)定义。 这是一个宣言。 编译器不会分配存储空间的i
在这个对象,但是当你在程序中使用它在其他地方它会识别变量。
int i
告诉编译器用于分配存储i
。 这是一个定义。 如果其他C ++(或C)文件具有int i
,链接器将抱怨,即INT I被定义了两次。
static int i
类似于上述情况,与额外的功能是i
是本地的。 它不能从其他模块访问,即使他们宣称extern int i
。 人们使用关键字static(在这方面),以保持我本地化。
因此,有i
两个声明被定义在其他地方,并在模块似乎是一个错误定义为静态。 Visual Studio是沉默的,和g ++是沉默只在一个特定的顺序,但无论哪种方式,你只是不应该有相同的源代码两条线。
C ++:
7) 在没有存储类说明符一个命名空间范围中声明的名称有外部链接,除非它有因为先前声明的内部连接和设置它不声明为const。 对象声明为常量,而不是明确声明为extern有内部链接。
所以,第一个尝试首先给i
外部链接和内部算账。
第二个给它内部连接第一,第二行不会尝试给它外部链接,因为它以前作为内部声明。
8)通过连续声明对于给定实体隐含的联系应同意。 即,一个给定的范围内,每个声明声明相同的变量名或函数名的相同的过载应意味着相同的键。 在一组给定的重载函数的每个功能可以具有不同的连接,但是。
[实施例:
[...]
static int b; // b has internal linkage
extern int b; // b still has internal linkage
[...]
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
[...]