在变量定义之前转到 - 它的值会发生什么?

Joh*_*itb 17 c++ goto local-variables register-allocation

这是我想知道的一些问题.鉴于以下代码,我们可以确定其输出吗?

void f() {
  int i = 0; 
  z: if(i == 1) goto x; else goto u; 
  int a; 
  x: if(a == 10) goto y; 
  u: a = 10; i = 1; goto z; 
  y: std::cout << "finished: " << a; 
}
Run Code Online (Sandbox Code Playgroud)

这是否保证finished: 10根据C++标准输出?或者编译器可以占用a存储到的寄存器,何时goto到达之前的位置a

Dev*_*lar 6

注意:首先阅读这篇评论.约翰尼斯或多或少地用一个很好的标准报价击败了我的整个论点.;-)


我没有C++标准,所以我必须从C标准中推断出来.

令人惊讶的是(对我来说),第6.2.1章标识符的范围没有说明从其声明开始的标识符的范围(正如我猜测的那样).int a在你的例子中,有块范围,它"终止于相关块的末尾",这就是所说的全部内容.第6.8.6.1章goto语句说"goto语句不应该从具有可变修改类型的标识符范围之外跳转到该标识符的范围内" - 但是因为你的gotos只块中跳转(并且,因此,范围int a,这似乎是确定尽可能ISO/IEC 9899:1999关注.

我对此感到非常惊讶......

编辑#1:快速谷歌后来我得到了C++ 0x最终草案.我认为,相关的声明就是这里(6.7 宣言声明,突出我的声明):

可以转换为块,但不能以初始化绕过声明的方式.从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的,除非该变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始化程序的情况下声明.

我认为按照标准的标准你的代码是可以的.但是,对不起,请注意.;-)

编辑#2:阅读关于int a由于向后跳跃可能造成的破坏的评论,我发现了这个(6.6 跳转语句,突出了我的):

从循环中移出一个循环,或者从 具有自动存储持续时间的初始化变量返回过去涉及销毁具有自动存储持续时间的对象,这些对象在转移点但不在转移点处的范围内.

一,int a不是"初始化",如果我正确理解标准术语,它不是一个对象.


Mar*_*k B 5

6.7/3说

除非变量具有POD类型(3.9)并且声明没有初始值设定项(8.5),否则从具有自动存储持续时间的局部变量不在范围内的点跳转到其在范围内的点的程序将被编码.

所以这应该没问题.

然后在6.6/2:

在从范围退出(但是已完成)时,将为所有具有自动存储持续时间(3.7.2)(命名对象或临时值)的构造对象调用析构函数(12.4),这些对象在其范围内声明,其声明的顺序与其声明的顺序相反.

现在这对我来说意味着a当你跳回来时是吐司,z并且你无法保证a第一次执行时no-initializer声明将如何表现.

见6.7/2:

每次执行声明声明时,都会初始化具有自动存储持续时间(3.7.2)的变量.块中声明的具有自动存储持续时间的变量在从块(6.6)退出时被销毁.

因此,在我看来,虽然似乎很难想象一个编译器不会出现这种情况,但是不能保证你会得到10.

  • "似乎很难想象编译器会出现这种情况." - 如果它是合法的,我可以想象它.比较`i == 1`可能通过将`i`复制到寄存器中,将`1`复制到寄存器中并进行比较来实现.同时,优化器可能已经决定将`a`存储在寄存器中.最后,可以将相同的寄存器分配给"a"和"1",因为执行比较时"a"不在范围内. (2认同)

Ren*_*ter 0

不允许放弃变量定义。这应该是一个错误。