我正在尝试理解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”的声明...I不理解到底发生了什么。我认为在“链接”阶段之后会出现错误,因为ODR冲突。我只能在编辑main.cpp文件时出现以下错误:
#include "pr1.cpp"
#include "pr2.cpp"有人能给我解释一下发生了什么事吗?
发布于 2017-07-31 23:00:38
除非在同一个文件中包含这两个定义,否则不会有任何问题。这是因为编译器对单个翻译单元进行操作,该翻译单元通常是一个.cpp文件。您在此文件中#include的所有内容也是翻译单元的一部分,因为预处理器基本上复制并粘贴所有包含的文件的内容。
编译器将为每个翻译单元创建目标文件(通常为.obj),然后链接器将通过链接所有目标文件和项目所依赖的库来创建单个可执行文件(或.dll等)。在您的例子中,编译器在不同的翻译单元中遇到每个结构,因此不会发现问题。当您包含这两个文件时,两个定义现在发现它们在同一个转换单元中,并且编译器会抛出一个错误,因为如果在这个转换单元中使用了S,编译器就无法解决歧义(即使您不必使用一个来使程序格式不正确)。
注意,不要在其他.cpp文件中包含.cpp文件。我相信您可以找到很多关于如何在头文件和源文件中组织代码的内容,但它并没有直接回答这个问题,所以我不再赘述了。
编辑:我忘了说为什么你没有得到一个链接器错误。一些评论指出,这是未定义的行为,这意味着即使您的链接器可能会抱怨,它实际上也没有必要这样做。在本例中,每个结构和一个main.obj都有一个.obj文件。这些都不引用另一个,因此链接器看不到任何它需要解析的引用,并且它可能不会检查不明确的符号。
我假设如果您声明了struct S;并尝试使用S*或S& (实际的S需要在同一转换单元内定义),大多数链接器都会抛出错误。这是因为链接器需要解析该符号,并且它会找到两个匹配的定义。考虑到这是未定义的,但是,符合标准的链接器可以只选择一个,并默默地将您的程序链接到一些无意义的东西,因为您打算使用另一个。对于从一个.cpp传递到另一个的结构来说,这可能特别危险,因为定义需要保持一致。当通过库边界传递同名的结构/类时,这也可能是一个问题。出于这些原因,请始终避免重复名称。
https://stackoverflow.com/questions/45418939
复制相似问题