如果使用goto将控制转移到if(false)块,会发生什么?

18

我在尝试解决一个复杂的“嵌套条件”问题时,想到了以下代码:

goto error;
    
if (false)
{
error:
    cout << "error block" << endl;
}
else
{
    cout << "else block" << endl;
}
当我运行这段代码时,只有错误块被显示出来,正如预期的那样(我猜?)。但是这是否是所有编译器都定义好的行为?

4
我们可以帮助解决您的“嵌套条件”问题,这比使用“goto”更好。 - Jarod42
12
这是一个合理的编程问题。让我们不要因为代码中出现了“goto”就自动对这个问题进行贬低评价。仅仅因为你不同意这个问题的前提并不意味着它是一个糟糕的问题。请注意,任何人在提出问题时都应该得到尊重和耐心回答。 - François Andrieux
6
听起来你担心会跳转到无法访问的代码。你可能担心该分支会被优化掉并在运行时不存在。但是,该分支有一个标签,并且存在一个goto到该标签的事实意味着它实际上是可达的。 - François Andrieux
尽管goto声名狼藉,但在某些情况下它是一个不错的选择(或者至少是较小的恶)。Objective-C(以及间接地,Objective-C++)在Cocoa代码中经常使用goto进行错误检测和跳转到资源清理 - 尽管这些是堂兄弟语言而不是C++本身。更严格的C++场景是一些状态机可以用goto优雅地表达,或者用更扭曲/复杂的方式避免goto(可能效率更低...但我不应该低估聪明的优化器)。 - Eljay
通常发生的情况是提交在代码审查中被否决。您的经验可能会有所不同。 - n. m.
2个回答

14

是的,这是被很好地定义了。请参阅stmt.goto#1

goto语句无条件地将控制转移到由标识符标记的语句。该标识符应为当前函数中的标签。

有一些限制,例如,case标签不能跨越非平凡初始化。

goto error;
int i = 42;
error:       // error: crosses initialization of i

但这些不适用于你的例子。此外,在初始化交叉的情况下,这是一个严格的编译器错误,因此您无需担心未定义的行为。


请注意,一旦跳转到error标签,您实际上位于if条件的真分支中,而且不管您是通过goto到达的,都无关紧要。因此,保证不会执行else分支。


我认为他们可能更关心的是如果不执行if条件,可能会导致跳转到if后跳过else块。 - Barmar
@Barmar 是的,没错。我已经添加了关于这个的解释。 - cigien
用一个 int 初始化另一个 int 不是很简单吗?std::is_trivially_constructible<int, int>::valuetrue - NotNik.
为避免术语问题,标准在这种情况下使用术语“空初始化”(基本上意味着“不执行任何操作”)。@NotNik。 - bogdan

1

我的看法:

如果你的编译器有优化器,代码会按以下方式减少:

// more code here
goto error; // this go directly to the label
    
if (false)
{
error:
    cout << "error block" << endl;
    // this skips else clause
}
else
{
    cout << "else block" << endl;
}
// more code here

因此,编译后的代码只是这样的:

所以编译后的代码只是这样的:

// more code here
{
    cout << "error block" << endl;
}
// more code here

这里是Godbolt的链接:

https://gcc.godbolt.org/z/nY6E166Pz

我稍微简化了代码,这样汇编就更易读了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接