以下C ++程序编译得很好(g ++ 5.4至少在使用-Wall
调用时发出警告):
int main(int argc, char *argv[])
{
int i = i; // !
return 0;
}
甚至像
这样的东西int& p = p;
编译器吞下了。
现在我的问题是:为什么这样的初始化合法?是否有任何实际的用例,或者它只是语言的一般设计的结果?
答案 0 :(得分:0)
仅仅因为编译器接受它(语法上有效的代码)而不是意味着它具有良好定义的行为。
编译器不需要来诊断未定义行为或其他类问题的所有情况。 该标准允许它非常自由地接受和翻译损坏的代码,假设如果结果是未定义的或无意义的,程序员就不会编写该代码。
因此;来自编译器的警告或错误的缺失不会以任何方式证明您的程序具有明确定义的行为。 遵守语言规则是您的责任。 编译器通常会试图通过指出明显的缺陷来帮助你,但最后它是你以确保你的程序有意义。
像int i = i;
这样的东西没有意义,但语法正确,所以编译器可能会或可能不会警告你,但无论如何都在其生成垃圾的权利范围内(而不是告诉你它)因为你违反了规则并调用了未定义的行为。
答案 1 :(得分:0)
我想您的问题的要点是为什么第二个标识符被识别为与int i = i;
或int &p = p;
这在C ++ 14标准的[basic.scope.pdecl] / 1中定义:
名称的声明点在其完整的声明者之后和初始化者之前(如果有的话),除非如下所述。 [实施例:
unsigned char x = 12; { unsigned char x = x; }
这里第二个
x
用自己的(不确定的)值初始化。 - 例子]
其他线程涵盖了这些语句的语义:
注意 - 引用的示例与int i = i;
的语义不同,因为评估未初始化的unsigned char
不是UB,而是UB来评估未初始化的int
。
如链接线程所述,g ++和clang在检测到时会发出警告。
关于范围规则的基本原理:我不确定,但范围规则存在于C中,所以它可能只是进入C ++,现在改变它会很困惑。
如果我们确实声明声明的变量不在其初始化程序的范围内,那么int i = i;
可能会使第二个i
从外部作用域找到i
,这也是混乱。
答案 2 :(得分:0)
这是规则的副作用,即名称在声明后立即在范围内。没有必要使这个简单的规则复杂化,只是为了防止编写明显无意义的代码。