除了任何功能之外,int x;
is a 暂定定义,一些编译器和链接器将它们视为一种“协作定义”,其中可以在多个文件中以这种方式声明标识符,并且将导致仅定义一个对象。
由于历史的原因,C 的外部声明(函数外部的声明)规则有点复杂——C 是随着不同的人开发和实验而成长的,而不是根据我们今天所拥有的知识进行设计的。
定义: int x = 3;
是一个定义。它都声明了标识符x
并为一个保留内存int
,并且它初始化int
to 3.
声明: extern int x;
是声明但不是定义。它声明了标识符x
但不为其保留内存。
extern int x;
gives x
外部链接也是如此int x = 3;
如果它出现在函数之外。外部链接意味着,当它们出现在不同的源文件中时,标识符的两个实例将被链接以引用内存中的同一事物。
C 标准规定,具有外部链接的标识符“应有”至多一个定义 (C 2018 6.9 5)。 (如果程序中使用了标识符,则必须有定义。如果表达式中没有使用标识符,则不需要定义。)
暂定定义: int x;
是一个混合体。在函数之外,它是一种特殊的声明,称为暂定定义。 C 标准规定,如果翻译单元(正在编译的源文件及其包含的所有文件)中有暂定定义,并且没有常规定义,则将创建常规定义。
现在,如果你违反了“最多应该有”一个定义的规则,会发生什么?事情是这样的:这不是程序必须遵守的规则。当 C 标准说“应该”时,意味着如果程序遵守此规则,则行为将如 C 标准所述。如果程序违反此规则,C 标准不会定义该行为 (C 2018 4 2)。相反,我们让编译器和链接器定义行为,如果它们的设计者选择这样做的话。
当程序违反最多一个定义的规则时,编译器和链接器中的一种常见行为(但不是唯一的可能性)是:
- 如果链接时有多个正则定义,则报错。
- 如果有多个定义来自暂定定义,但来自常规定义的定义不超过一个,请将它们合并为一个定义。
这是 GCC 版本 10 之前的 GCC 和相关工具中定义的默认行为,并在 C 2018 标准 J.5.11 中有关常见扩展的信息部分中明确提到。在当前版本的 GCC 中,任何类型的多个定义默认都会被视为错误。您可以使用命令行开关请求旧行为-fcommon
.