int foo = foo的标准参考

Roh*_*an 19 c++ undefined-behavior

int foo = foo;编译.C++标准的哪一部分允许这个?

Pra*_*rav 26

3.3.1声明点[basic.scope.pdecl]

名称的声明点紧接在其完整的声明者(第8条)之后和其初始化者(如果有的话)之前,

如果声明位于文件范围,则行为已明确定义.如果您在函数范围内有声明,并且foo稍后使用[在这种情况下将初始化为某些未指定的值],则行为将是未定义的.

  • @Tomalak:代码*可能*有UB,但不一定.OP似乎完全意识到它不是应该真正使用的东西,并且对它为什么要编译的纯粹学术观点感到好奇. (5认同)
  • 我会+1,但你完全没有提到OP的程序有未定义的行为而且_不应该被使用_. (4认同)
  • @Jerry:仙女. (2认同)

Lig*_*ica 21

这个?

int main() {
  int foo = foo;
}
Run Code Online (Sandbox Code Playgroud)

该对象foo确实存在之后=,根据[basic.scope.pdecl]:

名称的声明点紧跟在其完整的声明符(第8节)之后和其初始化器之前(如果有的话).

但是,整个程序是未定义的,因为您使用(在RHS上)未初始化的值:

int x = x; 这里[..] x用它自己的(不确定的)值初始化.

和:

虽然"推断和虐待指定"由标准,一个左值到右值转换是在RHS表达式进行的foo.

和([conv.lval]):

可以将非函数非数组类型T的左值(3.10)转换为右值.如果T是不完整类型,则需要进行此转换的程序格式不正确.如果左值引用的对象不是类型T的对象,并且不是从T派生的类型的对象,或者如果对象未初始化,则需要此转换的程序具有未定义的行为.

有了适当的警告级别,你就会被告知 ; 但是,允许编译调用未定义行为的程序.当你运行它们时,它们可以做任何事情.


或者,这个呢?

int foo = foo;    
int main() {}
Run Code Online (Sandbox Code Playgroud)

请注意,这foo是一个"全球".根据以下内容,这些是零初始化的第一步[basic.start.init]:

具有静态存储持续时间(3.7.1)的对象应在任何其他初始化发生之前进行零初始化(8.5).

所以你得到的int foo值是0; 在这一点上,它是有效的,[basic.scope.pdecl]如上所述,并按照[stmt.decl]:

具有静态存储持续时间(3.7.1)的所有本地对象的零初始化(8.5)在任何其他初始化发生之前执行.[..]

然后将值初始化为foo(自身),即0.

这是明确定义的...如果有点神秘.


为了彻底,这是第三个也是最后一个案例:

int foo = 42;
int main() {
   int foo = foo;
}
Run Code Online (Sandbox Code Playgroud)

可悲的是,这与第一种情况相同.由于在foo初始化程序计算之前已经声明了本地并且在范围内,因此初始化程序使用本地,foo并且您仍然处于未定义行为状态.全局foo未使用.