17

这是我想知道的一些问题。给定以下代码,我们可以确定它的输出吗?

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; 
}

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

4

4 回答 4

6

注意:首先阅读对此的评论。约翰内斯或多或少地用一句恰如其分的标准引语否定了我的整个论点。;-)


我没有可用的 C++ 标准,所以我必须从 C 标准推断。

令人惊讶的是(对我来说),第 6.2.1 章标识符的范围没有说明从声明点开始的标识符的范围(正如我猜想的那样)。int a,在您的示例中,具有块范围,它“在关联块的末尾终止”,这就是关于它的全部内容。第 6.8.6.1 章goto 语句说“goto 语句不应从具有可变修改类型的标识符的范围之外跳转到该标识符的范围内” - 但因为您goto的 s 仅块内跳转(并且,因此,就 ISO/IEC 9899:1999 而言int a,的范围似乎没问​​题。

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

编辑#1:稍后我快速搜索了一下 C++0x 最终草案。我认为相关的声明是这里(6.7声明声明,突出显示我的):

可以转移到一个块中,但不能以一种绕过初始化声明的方式。除非变量具有标量类型、具有普通默认构造函数和普通析构函数的类类型、以及这些类型之一的 cv 限定版本,或上述类型之一的数组,并且在没有初始化器的情况下声明

我认为您的代码符合标准的标准。但屁股丑陋,请注意。;-)

编辑#2:阅读您关于int a由于向后跳转而可能破坏的评论,我发现了这一点(6.6 Jump statements,突出显示我的):

转移出循环、转移出块或返回具有自动存储持续时间的初始化变量 涉及销毁具有自动存储持续时间的对象,这些对象在转移点的范围内但不在转移点的范围内。

一,int a不是“初始化”,如果我正确理解标准术语,它不是对象。

于 2011-07-22T14:22:22.380 回答
5

6.7/3 说

除非变量具有 POD 类型 (3.9) 并且在没有初始化程序 (8.5) 的情况下声明,否则从具有自动存储持续时间的局部变量不在范围内的点跳转到它在范围内的点的程序是错误的。

所以应该没问题。

然后在 6.6/2 中:

在从范围退出时(无论如何完成),对于在该范围中声明的所有具有自动存储持续时间 (3.7.2) 的构造对象(命名对象或临时对象),按照其声明的相反顺序调用析构函数 (12.4)。

现在这对我来说意味着a当你跳回时z,你不能保证 no-initializer 声明a在第二次执行时将如何表现。

见 6.7/2:

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

所以在我看来,不能保证你会得到 10 个,尽管似乎很难想象一个编译器不会出现这种情况。

于 2011-07-22T14:31:01.537 回答
0

是否保证finished: 10按照 C++ 标准输出?

我想是的,它必须!

为什么 ?因为a从它的声明到它的作用域结束(函数结束)并且根据定义它只能被初始化一次并且从那里保持它的值直到函数结束时的销毁。

于 2011-07-22T18:52:35.397 回答
0

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

于 2011-07-22T14:08:28.733 回答