Compiler construction 为什么编译器不能(总是?)优化已转到的代码?

Compiler construction 为什么编译器不能(总是?)优化已转到的代码?,compiler-construction,goto,Compiler Construction,Goto,我已经编写了一些PL/SQL程序,在这些程序中我发现GOTO很有用,比如跳出嵌套循环等等 我一直在想,在其他语言中使用gotos是否真的是个坏主意。 (例如C++)< /P> 我发现这些问题: 答案是:“编译器通常无法优化包含GOTO的代码。” 在另一个例子中:“但是,有可能生成一个gotos流图,而gotos不能由任何正常的流控制语句(循环、开关等)生成。” 有人告诉我这是goto邪恶,但没有人告诉我为什么,除了goto的代码读起来很恐怖。好吧,如果没有人学习、理解如何使用它们,因为它们是

我已经编写了一些PL/SQL程序,在这些程序中我发现GOTO很有用,比如跳出嵌套循环等等

我一直在想,在其他语言中使用gotos是否真的是个坏主意。 (例如C++)< /P> 我发现这些问题:

答案是:“编译器通常无法优化包含GOTO的代码。”

在另一个例子中:“但是,有可能生成一个gotos流图,而gotos不能由任何正常的流控制语句(循环、开关等)生成。”

有人告诉我这是goto邪恶,但没有人告诉我为什么,除了goto的代码读起来很恐怖。好吧,如果没有人学习、理解如何使用它们,因为它们是“邪恶的”,那么就没有人能够阅读它们

编译器可以和不能优化包含GOTO的代码的情况是什么?为什么?

大肥肉免责声明:

我一直在想,在其他语言中使用gotos是否真的是个坏主意。(例如C++)< /P> 除了一个例外(C,如下所述),它与大量的纪律结合在一起,它几乎从来都不是一个好主意。它依赖于语言,所以请询问您当地的专家,但是您找到一个好用例的可能性非常小。偏于谨慎。这种语言很可能有一种更为惯用、更清晰的方式来完成你想用的任何事情


与其说这是一个“永远不可能”或停止不可能的问题,不如说是“不切实际”。有时,特别是如果您只是通过手动编写等价的
goto
s来隐藏循环(这是多么愚蠢的事情啊!),它可能会碰巧起作用。在其他时候,特别是如果控制流图类似于意大利面条或其他奇怪/不寻常的情况下,编译器可能无法优化任何内容

在创建优化过程中投入的时间和思想只有这么多,编译器运行优化过程的时间也只有这么多。关注大多数语言中广泛使用的、易于理解的控制流模式(while循环、具有已知起始行程计数的循环、早期
返回
开关
、else if链等)更有意义。即使优化发生在只支持
goto
-esque控制流的IR上,这些模式也会导致可预测的、易于识别的伪装,并且优化会被调整以寻找这些伪装。这就是你引用的第二句话所说的。如果代码以一种完全不同于循环的方式来回跳转,那么循环展开过程不会给它一天中的时间,即使它实际上是一种聪明的(不太聪明的)写“做四次”的方式

到目前为止,我一直假设一个类似于标准C的
goto
——也就是说,目标标签是静态已知的,并且仅限于支持其他语言构造(例如,一个函数内仅跳转)。有一些扩展允许跳转到任意、动态选择的目标(例如“计算转到”)。这些函数更难分析(因此也更难优化),很可能与函数指针处于相同的范围内

有人告诉我这是goto邪恶,但没有人告诉我为什么,除了goto的代码读起来很恐怖。好吧,如果没有人学习、理解如何使用它们,因为它们是“邪恶的”,那么就没有人能够阅读它们

然后那些告诉你的人做得不好。这不是它的问题,所以我将保持它的简短:99%的控制流适合于极少数需要专门控制流构造的类别。使用一个单独的构造GOTO,因为所有这些情况都模糊了意图,它需要更多的代码,并且需要更长的时间来大致理解代码在做什么。您可以亲身体验:编写一些相当复杂的>100行批处理文件(这是一种可怕的古老Windows脚本语言)

啊,还有一件事:

我发现GOTO很有用,比如跳出嵌套循环

这可能是一个很好的用途,但大多数语言都提供了更清晰的方法。或者,将循环展平(例如,使用Python的
itertools.compositions
)和
break
,或者将嵌套的循环放入单独的函数中(在许多情况下这是个好主意)和
return


此外,这些都是
goto
的良好用途。例如,C语言中的错误处理。这些用例通常也遵循一种简单的模式,但这种模式没有内置到语言中,因此人们只能将就着不使用。

。。。如果没有goto,要有效地编写任意有限状态机的代码是非常困难的。同意德尔南的其余评论。@IraBaxter好吧,
而(1)切换(状态)
也不错。我非常清楚可能会生成什么样的代码以及需要做什么额外的工作,但我不能关心自己,我怀疑这对大多数软件来说都很重要(多少钱,每次转换50个周期?)。如果我需要这种级别的性能,我想我可能会付出额外的努力,创建一个eDSL来处理这些事情(或者使用一个现有的eDSL,如果适用的话),或者在汇编中编写整个内容。开关(状态)会在每个循环中导致管道中断。如果你不在乎,那么你就不在乎,否则你会在乎,直接转到更好。仅仅为了做一个简单的跳转就不得不跳出语言之外,这是一种耻辱。我同意,大多数程序不需要这个,但在不需要的地方编写结构化代码就足够容易了。但是大多数代码都不需要用任何编译语言编写。