C和链接中的暂定义

问题描述 投票:32回答:3

考虑由两个文件组成的C程序,

在f1.c:

int x;

f2.c:

int x=2;

我对the C99 standard第6.9.2段的解读是该程序应该被拒绝。在我对6.9.2的解释中,变量x暂时在f1.c中定义,但是这个暂定的定义在翻译单元的末尾变成了一个实际的定义,并且(在我看来),应该表现得好像f1.c包含定义int x=0;

对于所有编译器(以及重要的是,链接器)我能够尝试,这不是发生的事情。我试过的所有编译平台都链接了上面两个文件,两个文件中x的值都是2。

我怀疑这是偶然发生的,或者只是作为标准要求提供的“简单”功能。如果你考虑一下,这意味着链接器中对那些没有初始化器的全局变量有特殊支持,而不是那些显式初始化为零的全局变量。有人告诉我,无论如何编译Fortran可能都需要链接器功能。那将是一个合理的解释。

有什么想法吗?对标准的其他解释?文件f1.cf2.c拒绝链接在一起的平台名称?

注意:这很重要,因为问题出现在静态分析的上下文中。如果这两个文件可能拒绝在某个平台上链接,分析器应该抱怨,但是如果每个编译平台都接受它,那么就没有理由对它进行警告。

c compilation fortran static-analysis c99
3个回答
28
投票

另见What are extern variables in C。在资料性附件J的C标准中提到这是一个共同的扩展:

J.5.11多个外部定义

对象的标识符可能有多个外部定义,有或没有明确使用关键字extern;如果定义不一致,或者初始化了多个,则行为未定义(6.9.2)。

Warning

正如@litb在这里指出的那样,正如我对交叉引用问题的回答所述,对全局变量使用多个定义会导致未定义的行为,这是标准的说法“任何事情都可能发生”。可能发生的事情之一是程序的行为与您期望的一样;和J.5.11大致相同,“你可能比你应得的更幸运”。但是一个依赖于外部变量的多个定义的程序 - 有或没有明确的'extern'关键字 - 不是一个严格符合的程序,并不保证在任何地方都可以工作。同等地:它包含一个可能会或可能不会显示自身的错误。


9
投票

标准中有一个称为“公共扩展”的东西,只要变量只初始化一次,就允许多次定义变量。见http://c-faq.com/decl/decldef.html

链接页面说这与Unix平台相关 - 我猜c99与c89相同 - 虽然它可能已被更多编译器采用以形成某种事实标准。有趣。


7
投票

这是为了澄清我对olovb评论的回答:

从“int x;”编译的目标文件的nm输出。在此平台上,符号前面带有'_',即变量x显示为_x。

00000000 T _main
         U _unknown
00000004 C _x
         U dyld_stub_binding_helper

从“int x = 1;”编译的目标文件的nm输出

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

从“int x = 0;”编译的目标文件的nm输出

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

从“extern int x;”编译的目标文件的nm输出

00000000 T _main
         U _unknown
         U dyld_stub_binding_helper

编辑:从“extern int x;”编译的目标文件的nm输出其中x实际用于其中一个函数中

00000000 T _main
         U _unknown
         U _x
         U dyld_stub_binding_helper
© www.soinside.com 2019 - 2024. All rights reserved.