一个定义规则 - 编译

时间:2017-07-31 14:43:03

标签: c++ g++ one-definition-rule

我想了解ODR。 我创建了一个文件pr1.cpp,如下所示:

RewriteCond %{REQUEST_URI}:%{HTTP_HOST} ^/IMG/(.*)/XPATH/home/(.*?)(XEXT\.[^:]+)?:(.*) [NC]

像这样的第二个文件pr2.cpp

struct S{
  int a;
};

和这样的主文件:

struct S {
  char  a;
};

我正在使用终端编译命令:

#include <iostream>

int main() { 
  return 0;
}

编译器没有发现任何类型的错误但是有两个类型为“S”的声明......我不明白究竟发生了什么......我想在“链接”阶段之后得到一个错误因为ODR违规.. 我只能在编辑main.cpp文件时得到错误:

g++ -Wall -Wextra pr1.cpp pr2.cpp main.cpp -o mypr

有人可以告诉我发生了什么吗?

1 个答案:

答案 0 :(得分:-1)

除非您在同一文件中包含这两个定义,否则没有问题。这是因为编译器在单个转换单元上运行,该转换单元通常是.cpp文件。此文件中#include的所有内容也都是翻译单元的一部分,因为预处理器基本上会复制并粘贴所有包含文件的内容。

编译器将为每个转换单元创建和对象文件(通常为.obj),然后链接器将通过链接所有目标文件和项目所依赖的库来创建单个可执行文件(或.dll等)。上。在您的情况下,编译器在不同的转换单元中遇到每个结构,因此它没有看到问题。当您包含这两个文件时,这两个定义现在发现它们位于同一个转换单元中,并且编译器会抛出错误,因为如果在此转换单元中使用S,它就无法解决歧义(即使您没有使用一个程序是不正确的。)

作为附注,请勿在其他.cpp文件中包含.cpp文件。我相信你可以找到很多关于如何在头文件和源文件中组织代码的内容,而且它没有直接回答这个问题所以我不会对它进行扩展。

编辑:我忽略了为什么你没有得到链接器错误。一些评论指出这是未定义的行为,这意味着即使你的链接器应该抱怨它实际上不必。在您的情况下,每个结构都有一个.obj文件和一个main.obj。这些都没有引用另一个,因此链接器看不到它需要解析的任何引用,它可能不会检查是否有歧义符号。

我假设如果您声明struct S;并尝试使用S*S&(实际S需要在同一翻译中定义,则大多数链接器会抛出错误单元)。这是因为链接器需要解析该符号,它会找到两个匹配的定义。但是,鉴于这是未定义的,符合标准的链接器可以选择一个并将您的程序静默链接到无意义的东西,因为您打算使用另一个。对于从一个.cpp传递到另一个.cpp的结构,这可能会特别危险,因为定义需要保持一致。当同名的结构/类通过库边界传递时,它也可能是一个问题。由于这些原因,请始终避免重复名称。