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

Jos*_*eld 15 c++ standards linker one-definition-rule c++11

该标准似乎意味着如果变量的定义没有使用,则对变量的定义数量没有限制(§3.2/ 3):

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

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

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

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

// other.cpp
int x;

// main.cpp
int x;
int main() {}
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*lis 12

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

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

  • 两个名称都有外部链接,否则两个名称都有内部联系,并在同一个翻译单元中声明; 和

  • 两个名称都指向同一名称空间的成员或同一类的成员,而不是继承.和

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

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

(我引用了完整的段落作为参考.后两个子弹不适用于此.)

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

这两个名称表示相同的变量.声明int x;定义了一个变量.因为程序中有两个这样的定义,所以程序中有两个变量.一个翻译单元中的名称"x"表示这些变量之一; 另一个翻译单元中的名称"x"表示另一个.因此,该计划是不正确的.

  • 您如何得出两个名称"x"不表示相同变量的结论? (2认同)
  • @ecatmur:§3.2[basic.def.odr]/5允许"可以有多个类类型的定义." 如果`class y {};`出现在两个翻译单元中,那么在两个翻译单元中,名称`y`表示_名为`y`_的类.只有一个名为`y`的类.在`namespace z {}`的情况下,"命名空间的定义可以拆分为一个或多个翻译单元的几个部分"(§7.3[basic.namespace]/1).两个翻译单元中的名称"z"指的是名为_z_的名称空间.只有一个名为`z`的命名空间. (2认同)
  • 要申请3.2p6或7.3p1,您需要已经决定(通过3.5p9)名称表示相同的实体.(这对内联函数至关重要,其中重载发挥作用.)3.5p9是对实现者的指令,而不是程序员; 它描述了翻译单位如何进行交流(2.1p2).否则,同一翻译单元中的两个定义将表示不同的实体,而3.2p1将毫无意义. (2认同)

eca*_*mur 5

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

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

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