请考虑以下代码:
struct X {
static const int i = 45;
};
void foo() {
const int* k = &X::i;
}
int main() {
}
如果不打开您最喜欢的编译器,您认为编译和链接这个简单的野兽的结果是什么?
有些人可能会惊讶于它不仅依赖于编译器,还依赖于其优化选项!例如,在gcc上,代码将拒绝与关闭的优化链接,但很乐意链接(并生成无法执行任务的可执行文件)与任何已启用的优化。
失败案例中的诊断会很有趣 - 找不到符号X::i
。启用优化的链接将成功,因为X::i
将被丢弃。
问题。编译器的正确行为是编译这段代码吗?由于X::i
没有链接,当被要求生成一个要求在此符号上链接的代码时,编译器是否应该抱怨?
答案 0 :(得分:3)
由于您odr-using i
取其地址,因此必须在课堂外定义:
const int X::i ;
违反此规则属于无需诊断类别,因此这是完全有效的行为:
非正式地说,如果一个对象的地址被采用,或者一个对象被使用了 引用绑定到它,如果函数是函数,则函数使用odr 打电话给它或其地址。如果是对象或函数 使用得很多,它的定义必须存在于程序的某个地方;一个 违反这是一个链接时错误。
这可能取决于编译器,优化级别等......
草案C ++标准部分3.2
[basic.def.odr]说:
每个程序都应包含每个非内联的一个定义 在该程序中使用的函数或变量;没有诊断 需要
一些注意事项:
i
可以在以后或在另一个翻译单元中定义。