C和链接中的暂定义

时间:2009-09-29 05:25:18

标签: c compilation fortran static-analysis c99

考虑由两个文件组成的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拒绝链接在一起的平台名称?

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

3 个答案:

答案 0 :(得分:28)

另见What are extern variables in C。这在C标准中以提供信息的附件J作为共同的扩展名提及:

  

J.5.11多个外部定义

     

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

警告

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

答案 1 :(得分:9)

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

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

答案 2 :(得分: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