一个定义规则 - 编译
One Definition Rule - compilation
我试图理解ODR。 我创建了一个文件 pr1.cpp如下所示:
struct S{
int a;
};
第二个文件 pr2.cpp像这样
struct S {
char a;
};
和这样的主文件:
#include <iostream>
int main() {
return 0;
}
我正在使用带有命令的终端进行编译:
g++ -Wall -Wextra pr1.cpp pr2.cpp main.cpp -o mypr
编译器没有发现任何类型的错误,但是有两个类型为"S"的声明...我不明白到底发生了什么。由于违反 ODR 规定,我想在"链接"阶段后出现错误。. 我只能编辑主文件.cpp文件时出现错误,添加:
#include "pr1.cpp"
#include "pr2.cpp"
谁能解释一下发生了什么?
除非在同一文件中包含这两个定义,否则没有问题。这是因为编译器在单个翻译单元上运行,该翻译单元通常是.cpp文件。您在此文件中#include
的所有内容也是翻译单元的一部分,因为预处理器基本上复制并粘贴所有包含文件的内容。
发生的情况是,编译器将为每个翻译单元创建和目标文件(通常为 .obj(,然后链接器将通过链接所有目标文件和项目所依赖的库来创建单个可执行文件(或.dll等(。在您的情况下,编译器在不同的翻译单元中遇到了每个结构,因此它看不到问题。当您包含这两个文件时,这两个定义现在会发现自己位于同一个翻译单元中,并且编译器会引发错误,因为如果在此翻译单元中使用S
,编译器将无法解决歧义(即使您不必使用一个翻译单元来使程序格式不正确(。
作为旁注,不要在其他.cpp文件中包含.cpp文件。我相信你可以找到很多关于如何在头文件和源文件中组织代码的信息,它没有直接回答这个问题,所以我不会展开它。
编辑:我忘了说为什么你没有收到链接器错误。一些评论指出,这是未定义的行为,这意味着即使您的链接器可能应该抱怨,它实际上也不必抱怨。在您的情况下,每个结构都有一个 .obj 文件和一个 main.obj。这些都没有引用另一个,因此链接器看不到任何需要解析的引用,并且可能不会费心检查不明确的符号。
我认为如果您声明struct S;
并尝试使用S*
或S&
,大多数链接器都会抛出错误(实际S
需要在同一翻译单元内定义(。这是因为链接器需要解析该符号,并且它将找到两个匹配的定义。但是,鉴于这是未定义的,符合标准的链接器可以只选择一个并静默地将您的程序链接到无意义的内容中,因为您打算使用另一个。这对于从一个.cpp传递到另一个的结构尤其危险,因为定义需要保持一致。当同名结构/类通过库边界传递时,也可能是一个问题。出于这些原因,请始终避免重复名称。
- 二叉排序树无法编译
- 编译时未启用intel oneApi CUDA支持
- 一个定义规则 - 编译
- 将 qi::lexeme 添加到灵气中的规则时编译失败
- 使用 bazel 从源代码构建张量流服务遇到错误:C++规则'@org_tensorflow//…'编译失败(出口 4)
- 无法为编译 SFML 项目创建 cmake 规则
- X3 解析规则不编译
- Boost.Spirit X3 编译时间因递归规则而爆炸
- 编译Cyanoboot:没有规则来实现目标
- 将规则生产绑定到我的结构成员时出现编译错误
- 语义规则的编译时执行
- 编译时是否需要短路评估规则
- 升灵气:轻微规则变化的编译错误
- 使用生成文件使用一个规则编译多个文件类型
- 为什么我的 boost::spirit 规则不编译用于解析列表列表?
- boost::spirit::qi具有相同的简单自适应结构属性的规则会导致编译错误
- 在单独的文件夹中编译对象,隐式规则不匹配
- Boost精灵规则与phoenix绑定到结构编译失败
- 电报编译流程:无规则制作目标'/usr/lib/libicutu.a'
- 安卓编译:没有规则来设定目标