如果我不使用变量,我可以跨翻译单元对它进行多个定义吗?
If I don't odr-use a variable, can I have multiple definitions of it across translation units?
该标准似乎暗示,如果不使用odr,则对变量的定义数量没有限制(§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
没有在任何地方使用 odr(据我所知),我看不出标准如何限制这一点。还是未定义的行为?
您的程序违反了链接规则。 C++11 §3.5[basic.link]/9 指出:
相同且在不同范围内声明的两个名称应表示相同 变量、函数、类型、枚举器、模板或命名空间(如果)
两个名称都有
外部联系,或者两个名称都有内部链接,并在同一翻译单元中声明;和
这两个名称都引用同一命名空间的成员或同一类的成员(而不是通过继承);和
当两个名称都表示函数时,函数的参数类型列表是相同的;和
当两个名称表示函数模板时,签名相同。
(我引用了完整的段落,供参考。 后两个项目符号在这里不适用。
在您的程序中,有两个名称x
,它们是相同的。 它们在不同的范围内声明(在本例中,它们在不同的翻译单元中声明)。 这两个名称都有外部链接,两个名称都引用同一命名空间(全局命名空间)的成员。
这两个名称不表示相同的变量。 声明int x;
定义一个变量。 因为程序中有两个这样的定义,所以程序中有两个变量。 一个翻译单元中的名称"x"表示这些变量之一;另一个翻译单元中的名称"X"表示另一个。 因此,该程序格式不正确。
你是对的,标准在这方面有问题。 我有一种感觉,这种情况介于 3.2p1(每个翻译单元最多一个定义,如您的问题)和 3.2p6(描述类、枚举、内联函数和各种模板如何跨翻译单元具有重复定义)之间的差距。
为了进行比较,在 C 中,6.9p5 要求(我的强调):
外部定义是外部声明,也是函数的定义 (内联定义除外)或对象。如果在表达式中使用了用外部链接声明的标识符(而不是作为结果为整数常量的
sizeof
或_Alignof
运算符的操作数的一部分),则在整个程序中的某个地方,标识符应该只有一个外部定义;否则,不得超过一个。
如果标准没有说明未使用变量的定义,那么你不能暗示可能存在多个:
当这个国际 标准省略了对 行为。
因此,它可以很好地编译和运行,或者可能会在翻译过程中停止并显示错误消息,或者可能会使运行时崩溃等。
编辑:见詹姆斯麦克内利斯回答标准确实有关于它的规则。
编译没有错误,错误在于其链接。默认情况下,您的全局变量或函数对其他文件(具有extern
存储)是公开的,因此在最后,当链接器想要链接您的代码时,它会看到两个x
定义,并且它无法选择其中一个,因此,如果您不使用other.cpp
中的main.cpp
x
,则使它们成为静态的(这意味着仅对包含它的文件可见)
// other.cpp
static int x;
// main.cpp
static int x;
- 不同翻译单元中不可重载的非内联函数定义
- 使用 Google Test 对自定义断言函数进行单元测试
- 是否允许类在程序中的不同翻译单元之间具有不同的定义?
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 为什么通过定义另一个指针单元格,整个代码停止工作?
- GCC 6.3.0 中的 ODR 冲突,类型在两个单独的翻译单元中定义
- 为什么结构和类定义可以在多个翻译单元上重复?
- 重新定义捕获单元测试
- 在名称中定义并在多个翻译单元中使用的变量的链接
- 命名空间的定义是否可以跨越多个翻译单元
- 使用单元测试 (cppunit) 中另一个文件中定义的结构时出错
- 如果我不使用变量,我可以跨翻译单元对它进行多个定义吗?
- 哪个翻译单元包含隐式定义的特殊成员函数
- 不同翻译单元中类的多重定义
- 是否可以通过在单元测试中定义我自己的 PRIVATE 宏来使私有成员公开
- 使用 extern 引用在不同编译单元中定义的函数
- 在VS2012单元测试中创建和测试自定义MFC CEdit时,在第21行的afxwin1.inl中断言
- 通过ifdef以编程方式确定是否在翻译单元中定义了标签
- 有没有一种方法可以在编译单元中隐藏C++类定义
- 在不同的翻译单元中的两个变量违反了一个定义规则