每个人都知道Dijkstra的《致编辑的信》:goto语句被认为是有害的(这里。html transcript和这里。pdf),从那时起,就有一种强大的推动力,尽可能避免使用goto语句。虽然可以使用goto来生成不可维护的、庞大的代码,但它仍然存在于现代编程语言中。即使Scheme中先进的连续控制结构也可以被描述为复杂的后向。

在什么情况下需要使用goto?什么时候最好避免?

作为一个后续问题:C提供了一对函数setjmp()和longjmp(),它们不仅提供了在当前堆栈帧内进行跳转的能力,还提供了在任何调用帧内进行跳转的能力。这些应该被认为和goto一样危险吗?更危险?


Dijkstra自己也对这个头衔感到后悔,因为这不是他的责任。在EWD1308的结尾(也在这里。pdf),他写道:

Finally a short story for the record. In 1968, the Communications of the ACM published a text of mine under the title "The goto statement considered harmful", which in later years would be most frequently referenced, regrettably, however, often by authors who had seen no more of it than its title, which became a cornerstone of my fame by becoming a template: we would see all sorts of articles under the title "X considered harmful" for almost any X, including one titled "Dijkstra considered harmful". But what had happened? I had submitted a paper under the title "A case against the goto statement", which, in order to speed up its publication, the editor had changed into a "letter to the Editor", and in the process he had given it a new title of his own invention! The editor was Niklaus Wirth.

Donald E. Knuth写了一篇关于这个主题的经典论文,它与Dijkstra的论文相匹配,那就是结构化编程与语句。阅读既有助于重建上下文,也有助于对主题的非教条性理解。在本文中,Dijkstra对这个案例的观点被报道,并且更加强烈:

Donald E. Knuth:我相信通过呈现这样一个 事实上,我并不是不同意 Dijkstra的观点,因为 他最近写道: “请不要落入。 相信我是可怕的 教条的关于[去]的教条的 声明)。我觉得很不舒服 感觉别人在做 宗教出来了,好像 编程的概念问题 只用一个小技巧就能解决,用什么 一种简单的编码纪律!”


当前回答

在C语言中,goto只在当前函数的范围内工作,这倾向于本地化任何潜在的错误。Setjmp和longjmp要危险得多,它们是非本地的、复杂的、依赖于实现的。然而,在实践中,它们太模糊和不常见,不会引起很多问题。

我认为在C中goto的危险被大大夸大了。请记住,最初的goto参数发生在老式BASIC等语言的时代,初学者会编写这样的意大利面条代码:

3420 IF A > 2 THEN GOTO 1430

这里Linus描述了goto的适当用法:http://www.kernel.org/doc/Documentation/CodingStyle(第7章)。

其他回答

实际上,我发现自己不得不使用goto,因为我真的想不出更好(更快)的方法来编写这段代码:

我有一个复杂的对象,我需要对它做一些操作。如果对象处于一种状态,那么我就可以进行快速操作,否则我就必须进行慢速操作。问题是,在某些情况下,在缓慢的手术过程中,可能会意识到这可以用快速手术来完成。

SomeObject someObject;    

if (someObject.IsComplex())    // this test is trivial
{
    // begin slow calculations here
    if (result of calculations)
    {
        // just discovered that I could use the fast calculation !
        goto Fast_Calculations;
    }
    // do the rest of the slow calculations here
    return;
}

if (someObject.IsmediumComplex())    // this test is slightly less trivial
{
    Fast_Calculations:
    // Do fast calculations
    return;
}

// object is simple, no calculations needed.

这是一个实时UI代码的速度关键部分,所以我真的认为GOTO在这里是合理的。

Hugo

在生成C状态机时,使用GOTO会很好。我永远不会在手写代码中使用GOTO——“现代”语言结构使它完全没有必要。

setjmp/longjmp构造在某些情况下(缺少“真正的”异常时,或者在实现Chicken scheme之类的东西时)可能有用,但在“普通”编程中没有它的位置。

后藤认为他很有帮助。

我从1975年开始编程。对于20世纪70年代的程序员来说,“goto被认为是有害的”这个词或多或少地表明,具有现代控制结构的新编程语言值得一试。我们确实尝试了新的语言。我们很快就皈依了。我们再也没有回去过。

我们再也没有回去过,但是,如果你更年轻,那么你就从来没有去过那里。

现在,拥有古老编程语言的背景可能并没有太大用处,除非它能显示程序员的年龄。尽管如此,年轻的程序员缺乏这方面的背景,所以他们不再理解口号“goto被认为是有害的”在引入时向目标受众传达的信息。

一个人不理解的口号是不太有启发性的。也许最好忘记这些口号。这样的口号无济于事。

然而,这个特别的口号,“后藤有害”,已经有了它自己的不死生命。

能去不被虐待吗?回答:当然,但那又怎样?实际上,每一个编程元素都可能被滥用。例如,普通bool被滥用的次数比我们中的一些人愿意相信的要多。

相比之下,自1990年以来,我不记得遇到过一次真正的goto滥用案例。

goto最大的问题可能不是技术问题,而是社交问题。不太懂的程序员有时似乎觉得不赞成goto会让他们听起来很聪明。您可能需要不时地满足这样的程序员。生活就是这样。

今天goto最糟糕的事情是它没有被充分使用。

我唯一同意使用Goto的地方是当你需要处理错误时,每一个特定的错误点都需要特殊的处理。

例如,如果您正在获取资源并使用信号量或互斥,您必须按顺序获取它们,并且应该始终以相反的方式释放它们。

一些代码需要一种非常奇怪的模式来获取这些资源,并且您不能仅仅编写一个易于维护和理解的控制结构来正确处理这些资源的获取和释放以避免死锁。

在没有goto的情况下总是可以做得很好,但在这种情况下和其他一些情况下,goto实际上是更好的解决方案,主要是为了可读性和可维护性。

亚当

原论文应该被认为是“无条件GOTO被认为是有害的”。它特别提倡一种基于条件(if)和迭代(while)结构的编程形式,而不是早期代码常见的测试-跳转。Goto在某些语言或环境中仍然有用,因为这些语言或环境不存在适当的控制结构。