如何在c ++中应用ODR(一个定义规则)?

时间:2017-04-22 15:14:37

标签: c++

我阅读了Definitions and ODR页面,并且还阅读了有关ODR的几个相关问题。仍然不明白为什么它很重要。

例如,在file1.cpp中:

int val = 2;

在file2.cpp中:

extern int val;

在main.cpp中:

NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *myDate = [df dateFromString:@"2017-06-23 15:34:48"];
NSLog(@"%@", myDate);

此案件违反了ODR。但在实际情况下,有人会这样做吗?我的意思是一个具有相同类型相同名称的变量的定义似乎是自然的。即使有人这样做,编译器或链接器也不会同意。我不明白为什么我们应该关心ODR,因为如果我们编写错误的代码,编译器或链接器将给出错误。是否有可能在未被发现的情况下违反ODR?任何人都可以列出我们经常犯的一些真实案例或错误吗?

2 个答案:

答案 0 :(得分:3)

  

我不明白我们为什么要关心ODR,因为如果我们写错了代码,编译器会给出错误。

ODR是唯一允许编译器发出错误消息的东西。如果我们没有ODR,编制者将被要求接受此类代码。

  

可以在编译代码时违反ODR吗?

不确定。根据编译器的不同,这可能会编译和链接而不会出现任何问题,或者可能会失败:

extern int var;
int main() {
  int myvar = var;
}

请注意此处缺少var的定义。

有些编译器发现局部变量myvar完全未使用,因此也删除了对var的引用。其他编译器/链接器会抱怨缺少var的定义。而对于其他一些,它取决于您传递的编译器标志。

另一个例子:

// t1.cc
int var;
// t2.cc
long var;

有些编译器会为int varlong var提供相同的内部名称并检测冲突,其他编译器会包含类型,并且不会发现任何冲突。

答案 1 :(得分:2)

关于修理案例的小注释

您可以在翻译单元或匿名名称空间中将此变量声明为static

static全局变量确实具有内部链接,因此不会违反ODR。

file1.cpp

 static int val = 1;
 // OR
 namespace
 {
   int val = 1;
 }

file2.cpp

static int val = 2;
// OR
namespace
{
  int val = 2;
}

来自现实生活的潜在案例

如果您有两个具有相同全局变量的DLL,并且您在应用程序中加载了两个共享库,那该怎么办?