c++中的一个定义规则
One definition rule in c++
根据c++标准:
任何翻译单元不得包含一个以上的任何定义变量、函数、类类型、枚举类型或模板
//--translation_unit.cpp--//
int a;
void foo()
{
int a; //Second defention of a. ODR fails.
}
你能解释一下ODR到底是怎么工作的吗?
这并不违反规则,因为您定义了两个不同的变量。它们具有相同的名称,但在不同的作用域中声明,因此是独立的实体。每个都有一个单独的定义。
函数作用域中的声明被称为隐藏全局命名空间中的声明。在函数中,限定名 a
指的是局部变量,限定名 ::a
指的是全局变量。
它们不违反ODR,因为它们具有不同的作用域。
第一个a
具有全局作用
已知具有全局作用域(也称为文件作用域)的变量在定义
之后的整个文件
第二个a
具有局部作用域
已知具有局部作用域(也称为块作用域)的变量仅在定义它的块内
为了更清楚地理解c++的ODR,你应该研究的概念是:存储持续时间,范围和链接
您没有重新定义a
。
您刚刚定义了一个新的变量a
。它的作用域仅在函数内部,与原函数无关(原函数具有全局作用域),并在函数内部遮蔽原函数。
你能解释一下ODR到底是怎么工作的吗?
下面是一个违反ODR的例子:
/* file : module.cpp */
#include <stdio.h>
inline int foo() {
printf("module.foo: %pn", &foo);
return 1;
}
static int bar = foo();
/* file : main.cpp */
#include <stdio.h>
inline int foo() {
printf("main.foo: %pn", &foo);
return 2;
}
int main(int argc, char *argv[]) {
return foo();
}
可以看到,函数int foo()
在两个模块中定义不同。现在观察它如何根据所请求的优化级别(O3 vs 0)产生不同的行为:
$ clang++ --std=c++11 -O0 main.cpp module.cpp && ./a.out
module.foo: 0x100a4aef0
module.foo: 0x100a4aef0
$ clang++ --std=c++11 -O3 main.cpp module.cpp && ./a.out
module.foo: 0x101146ee0
main.foo: 0x101146ee0
输出是不同的,因为对于内联函数编译器在每个编译模块中产生一个链接器符号。这个符号(在每个编译模块中)被标记为"任意选择,它们都是相同的"。在第一种情况下,当所有优化都被禁用时,链接器从module.cpp中获取定义。在第二种情况下,编译器只是内联两个函数,因此不需要链接器的额外工作。
还有其他违反ODR产生奇怪行为的例子。所以,不要这样做:)
注:奖励,来自现实生活的案例:
/* a.cpp */
struct Rect
{
int x,y,w,h;
Rect(): x(0),y(0),w(0),h(0)
};
/* b.cpp */
struct Rect
{
double x,y,w,h;
Rect(): x(0),y(0),w(0),h(0)
};
这里的问题与前面的示例相同(因为Rect构造函数是隐式内联的)。根据月球编译器的不同阶段,会选择一种实现或另一种实现,产生奇怪的结果(int
版本将留下doubles
的一部分未初始化,double
版本将在int
之外并损坏内存)。防止这种情况的好方法是使用匿名命名空间(c++)或将struct声明为static
(C):
/* file.cpp */
namespace {
struct Rect { ... };
}
/* file.c */
static struct Rect { ... };
相关文章:
- 此代码是否违反一个定义规则
- 静态结构和一个定义规则
- 为什么转换函数声明不需要至少一个定义类型说明符
- 只有一个定义/声明时标头声明变量的多堆定义错误
- 一个定义规则 - 编译
- 为什么传递给函数 set::itrator 而不是 const_iterator 违反了一个定义规则?
- 内联函数和一个定义规则
- 如何在C 中应用ODR(一个定义规则)
- C++ 多个定义,即使只给出了一个定义
- std::integral_constant<T, v>::value 总是有一个定义吗?
- 为什么这不违反一个定义规则
- C 是纯虚拟函数,也是一个定义或仅声明
- 从标准库重新定义函数是否违反了一个定义规则
- 是否使用“ __Date__”或“ __Time__”违反了一个定义规则
- 非静态数据成员和一个定义规则
- 如何在C++中声明一个定义为func(cv::Mat &img)的函数
- 现代C和C :可以将一个定义的结构用于其他声明的结构
- C 是平行阵列一个定义的结构
- 当一个定义位于命名空间中时不明确的函数调用
- C++:同名的文件范围常量违反了一个定义规则