如果我没有使用变量,我可以跨翻译单元对它进行多种定义吗?

时间:2012-10-19 16:44:04

标签: c++ linker c++11 standards one-definition-rule

标准似乎暗示如果变量的定义数不是 odr-used (§3.2/ 3),则对变量的定义没有限制:

  

每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。

确实说任何变量都不能在翻译单元中多次定义(§3.2/ 1):

  

任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义。

但我无法在整个程序中找到对非odr使用变量的限制。那么为什么我不能编译如下的内容:

// other.cpp
int x;

// main.cpp
int x;
int main() {}

使用g ++ 4.6.3编译和链接这些文件,我得到multiple definition of 'x'的链接器错误。说实话,我期待这一点,但由于x在任何地方都没有使用(据我所知),我看不出标准如何限制这一点。还是未定义的行为?

4 个答案:

答案 0 :(得分:12)

您的程序违反了链接规则。 C ++11§3.5[basic.link] / 9州:

  

两个相同且在不同范围内声明的名称应表示相同   变量,函数,类型,枚举器,模板或命名空间,如果

     
      
  • 两个名称都有外部链接,或者两个名称都有内部链接,并在同一个翻译单元中声明;以及

  •   
  • 这两个名称指的是同一名称空间的成员或同一类的成员,而不是继承。以及

  •   
  • 当两个名称都表示函数时,函数的参数类型列表是相同的;以及

  •   
  • 当两个名称都表示功能模板时,签名是相同的。

  •   

(我引用了完整的段落作为参考。后两个子弹在这里不适用。)

在您的程序中,有两个名称x,它们是相同的。它们在不同的范围内声明(在这种情况下,它们在不同的翻译单元中声明)。两个名称都有外部链接,两个名称都指向同一名称空间(全局名称空间)的成员。

这两个名称表示相同的变量。声明int x;定义了一个变量。因为程序中有两个这样的定义,所以程序中有两个变量。一个翻译单元中的名称“x”表示这些变量之一;另一个翻译单元中的名称“x”表示另一个。因此,该计划形成不良。

答案 1 :(得分:5)

你认为标准在这方面是错误的是正确的。我有一种感觉,这种情况属于3.2p1(每个翻译单元最多一个定义,如你的问题)和3.2p6(它描述了类,枚举,内联函数和各种模板如何具有重复定义)之间的差距翻译单位)。

为了比较,在C中,6.9p5需要(我的重点):

  

外部定义是外部声明,也是函数的定义   (内联定义除外)或对象。如果在表达式中使用了使用外部链接声明的标识符(除了作为结果为整数常量的sizeof_Alignof运算符的操作数的一部分),整个程序中的某处应该有正好是标识符的一个外部定义; 否则,不得超过一个

答案 2 :(得分:1)

如果标准没有说明未使用变量的定义,那么你不能暗示可能有多个:

  

本国际时也可能会出现未定义的行为   标准省略了任何明确定义的描述   行为。

因此它可以编译并运行得很好,或者可能在转换过程中因错误消息而停止,或者可能会使运行时崩溃等。

编辑:看到詹姆斯麦克纳利斯回答标准确实实际上有关于它的规则。

答案 3 :(得分:0)

编译时没有错误,错误在其链接中。默认情况下,您的全局变量或函数对其他文件是公共的(具有extern存储),因此在链接器想要链接您的代码时,它会看到x的两个定义,并且它不能选择其中一个它们,所以如果你不在x中使用main.cpp的{​​{1}}而反之则使它们成为静态的(这意味着只对包含它的文件可见)

other.cpp