图像中的文本是错误的,因为"外部"和"自动"并不像它所说的那样是应用于声明的默认说明符.extern
的效果取决于声明出现在哪里以及之前有哪些声明.文件范围内的声明int i;
不能说具有默认的extern
说明符,因为extern int i;
具有不同的效果,如下所述.
在文件范围内,int i;
是tentative definition,用于名为i
的对象(C 2018 6.9.2 2).尽管它的名字是tentative definition,但它并不是一个定义(就像面试中的潜在员工不是员工一样).如果翻译单元中没有常规定义,则临时定义将导致创建定义.然而,由于不同的C实现对int i;
的处理不同,C标准没有定义如果有多个定义会发生什么(C 2018 6.9 5,C 2018 4 2).一些C实现将多个由兼容的试验性定义产生的定义合并为单个定义.有些人认为这是一个错误.The default changed in GCC version 10.
在文件范围内,extern int i;
是名为i
的对象的declaration,该对象不是定义.它不为i
保留存储空间,如果在程序中使用i
,则必须在程序的其他地方为其定义.这个声明给i
外部链接unless一个先前的声明是可见的(见下文).
在文件范围内,extern int i = 0;
是名为i
的对象的definition.根据C标准的规则,带有初始化的声明是一个定义,即使它有extern
个,所以编译器应该将其视为一个定义.然而,C用户的惯例是不将extern
与定义一起使用.因此,使用extern
声明int i
,并使用= 0
提供初始化,这违反了该约定.但这只是用户的惯例,而不是C标准的规则.因此,编译器会警告这种违反约定的行为,但符合C标准的编译器必须接受这段代码作为i
的定义.(如果您将警告转换为错误,就像使用Clang或GCC的-Werror
switch 一样,编译器不接受此代码,并成为不符合标准的编译器.)
作为另一个复杂情况的例子,如果出现extern int i;
,其中可以看到先前将i
声明为static int i;
,则i
在extern int i;
处的链接是内部的,而不是外部的(C 2018 6.2.2 4).extern
的规则不能被声明为"它使链接位于外部",甚至不能被声明为"在文件范围内,它使链接位于外部".它的效果既取决于它的范围,也取决于之前的声明,使用C标准中不同位置声明的多个规则.