让我们从一个完全由C标准定义的例子开始。如果file.h包含extern int x;,它声明一个标识符x来引用某个int对象。这个声明在编译过程中是file_1.c和file_2.c的一部分,并且根据C 2018 6.2.2,它通过 linkage“使其引用同一个对象”。 在这种情况下,extern int x;仅仅是一个没有定义x的声明。其他声明必须定义x。这可以通过将int x;或int x = value;放在file_1.c或file_2.c中来完成。那么对您问题的回答将是多个源文件中的extern int x;将引用同一个对象。 在您询问file.h中的int x;的情况下,C标准没有完全定义该行为。根据C 2018 6.9.2,这是一个暂定定义。如果没有x的常规定义,C标准认为暂定定义导致x被定义为好像它被初始化为零。(相反地,具有初始设定式的宣告,例如int x = 0;,是一般定义,而不是暂定定义)。 在这种情况下,file_1.c和file_2.c都定义了x。因此,每个文件都有自己的定义。然后,C标准没有定义行为,根据6.9 5,这意味着这样的标识符不应有超过一个定义(如果它实际上在表达式中使用,则正好是一个)。 由于C标准没有定义行为,C实现可能会定义。直到最近,愚者、Clang和Unix工具都将临时定义与常规定义区别对待。允许多个临时定义,并且它们被合并形成一个定义。因此,在这种情况下,对您的问题的答案是混合的:当int x;出现在多个源文件中时,在编译过程中,名义上它指的是C标准的某些解释中的“不同”对象,但链接将其解析为同一对象。 愚者的最新版本改变了这种行为。默认情况下,暂定定义更像常规定义,因此多个暂定定义将导致链接错误。在这种情况下,您问题的答案是,当int x;出现在多个源文件中时,它引用不同的对象,这将阻止程序链接。 (This change in GCC started in version 10. The old behavior can be requested with the command-line switch -fcommon or by applying the attribute __attribute__((__common__)) to an identifier.)
1条答案
按热度按时间5n0oy7gb1#
让我们从一个完全由C标准定义的例子开始。如果
file.h
包含extern int x;
,它声明一个标识符x
来引用某个int
对象。这个声明在编译过程中是file_1.c
和file_2.c
的一部分,并且根据C 2018 6.2.2,它通过 linkage“使其引用同一个对象”。在这种情况下,
extern int x;
仅仅是一个没有定义x
的声明。其他声明必须定义x
。这可以通过将int x;
或int x = value;
放在file_1.c
或file_2.c
中来完成。那么对您问题的回答将是多个源文件中的extern int x;
将引用同一个对象。在您询问
file.h
中的int x;
的情况下,C标准没有完全定义该行为。根据C 2018 6.9.2,这是一个暂定定义。如果没有x
的常规定义,C标准认为暂定定义导致x
被定义为好像它被初始化为零。(相反地,具有初始设定式的宣告,例如int x = 0;
,是一般定义,而不是暂定定义)。在这种情况下,
file_1.c
和file_2.c
都定义了x
。因此,每个文件都有自己的定义。然后,C标准没有定义行为,根据6.9 5,这意味着这样的标识符不应有超过一个定义(如果它实际上在表达式中使用,则正好是一个)。由于C标准没有定义行为,C实现可能会定义。直到最近,愚者、Clang和Unix工具都将临时定义与常规定义区别对待。允许多个临时定义,并且它们被合并形成一个定义。因此,在这种情况下,对您的问题的答案是混合的:当
int x;
出现在多个源文件中时,在编译过程中,名义上它指的是C标准的某些解释中的“不同”对象,但链接将其解析为同一对象。愚者的最新版本改变了这种行为。默认情况下,暂定定义更像常规定义,因此多个暂定定义将导致链接错误。在这种情况下,您问题的答案是,当
int x;
出现在多个源文件中时,它引用不同的对象,这将阻止程序链接。(This change in GCC started in version 10. The old behavior can be requested with the command-line switch
-fcommon
or by applying the attribute__attribute__((__common__))
to an identifier.)