转到变量定义之前 - 它的值会发生什么?
这是我想知道的一些问题。给出以下代码,我们可以确定它的输出吗?
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;
}
根据 C++ 标准,这是否保证输出 finished: 10
?或者,当 goto
到 a
之前的位置时,编译器是否可以占用存储 a
的寄存器?
Here is some question I wondered about. Given the following code, can we be certain about its output?
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;
}
Is this guaranteed to output finished: 10
according to the C++ Standard? Or can the compiler occupy the register that a
is stored into, when goto
to a place prior to a
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
6.7/3 说
所以应该没问题。
然后在6.6/2中:
现在,这对我来说意味着,当您跳回到
z
时,a
就完蛋了,并且您无法对a
的无初始化器声明如何做出任何保证code> 将在第二次执行时表现出来。参见 6.7/2:
所以在我看来,并不能保证你会得到 10,尽管似乎很难想象编译器不会出现这种情况。
6.7/3 says that
So that should be ok.
Then in 6.6/2:
Now this implies to me that
a
is toast when you jump back toz
and you cant' make any guarantees about how the no-initializer declaration ofa
will behave the second time it executes.See 6.7/2:
So it looks to me like there isn't a guarantee that you'll get 10 although it seems hard to imagine a compiler where that wouldn't be the case.
注意:首先阅读对此的评论。约翰内斯或多或少用一句恰当的标准引语驳斥了我的整个论点。 ;-)
我没有可用的 C++ 标准,所以我必须从 C 标准推断。
令人惊讶的是(对我来说),第 6.2.1 章标识符的范围没有提及从声明点开始的标识符的范围(正如我所猜测的)。在您的示例中,int a 具有块作用域,它“在关联块的末尾终止”,这就是关于它的全部内容。第 6.8.6.1 章 goto 语句 说“goto 语句不得从具有可变修改类型的标识符的范围之外跳转到该标识符的范围之内” - 但因为您的
goto 只在块内跳转(因此,
int a
的范围,似乎可以作为根据 ISO/IEC 9899:1999对此感到非常惊讶...
编辑#1:很快我就得到了 C++0x 最终草案。我认为相关的声明在这里(6.7声明声明,突出显示我的):
我认为按照标准的标准,你的代码是可以的。但请注意,屁股很丑。 ;-)
编辑#2:阅读您关于由于向后跳转而可能破坏
int a
的评论,我发现了这个(6.6 跳转语句,突出显示我的):第一,
int a
不是“初始化”的,如果我正确理解标准术语,它也不是一个对象。Note: Read the comments to this one first. Johannes more or less shot down my whole argument with one well-placed standard quote. ;-)
I do not have the C++ standard available, so I have to extrapolate from the C standard.
Surprisingly enough (for me), chapter 6.2.1 Scopes of identifiers says nothing about the scope of an identifier starting at the point of its declaration (as I would have guessed).
int a
, in your example, has block scope, which "terminates at the end of the associated block", and that is all that is said about it. chapter 6.8.6.1 The goto statement says that "a goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier" - but since yourgoto
s jump around only within the block (and, thus, the scope ofint a
, that seems to be OK as far as ISO/IEC 9899:1999 is concerned.I'm quite surprised about this...
Edit #1: A quick google later I got my hands on the C++0x final draft. The relevant statement, I think, is this here (6.7 Declaration statement, highlighting mine):
I think your code is OK by the standard's standards. But butt-ugly, mind you. ;-)
Edit #2: Reading your comment about the possible destruction of
int a
due to the jump backwards, I found this (6.6 Jump statements, highlighting mine):One,
int a
is not "initialized", and it is not an object if I understand the standard terminology correctly.不允许放弃变量定义。这应该是一个错误。
It's not allowed to forgo a variable definition. It should be an error.
根据C++标准,是否保证输出
finished: 10
?我想是的,必须的!
为什么 ?因为
a
从它的声明开始一直到它的作用域结束(函数结束),并且根据定义它只能被初始化一次,并且从那时起保留它的值,直到在函数结束时被销毁。功能。Is it guaranteed to output
finished: 10
according to the C++ Standard?I think yes ,it must!
Why ? Because
a
lives from its declaration till the end of its scope (end of the function) and by definition it can only be initialized once and from there on retain its value until destruction which is at the end of the function.为什么不通过装配来确定这一点?
结论:局部变量只会声明一次;但是,每次都会执行作业。
理由如下。
我简化了问题:
main.cpp:
然后我在 Linux 上将其编译为程序集(其中
asm
的未注释):g++ -std=c++20 -I/usr/ include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -S main.cpp
输出main.s(main.cpp的汇编输出)。这是相关部分;我添加了一堆破折号以使其更加明显:
然后,我使用
以下命令编译了 main.cpp: g++ -std=c++20 -I/usr/include/c++/11 -I/usr/include/ x86_64-linux-gnu/c++/11 main.cpp -omain
它编译得很好。然后我用以下命令运行它:
./main
它陷入了无限循环。
Why not determine this with assembly?
Conclusion: The local variable will only be declared once; however, the assignments will all be performed each time.
Justification below.
I simplified the problem:
main.cpp:
Then I compiled this into assembly (with the
asm
's uncommented) on Linux with:g++ -std=c++20 -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -S main.cpp
which output main.s (the assembly output of main.cpp). Here is the relevant part; I added in a bunch of dashes to make it more obvious:
Then, I compiled main.cpp using:
g++ -std=c++20 -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 main.cpp -omain
It compiled fine. Then I ran it with:
./main
And it was stuck in an infinite loop.