每个人都知道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的观点,因为 他最近写道: “请不要落入。 相信我是可怕的 教条的关于[去]的教条的 声明)。我觉得很不舒服 感觉别人在做 宗教出来了,好像 编程的概念问题 只用一个小技巧就能解决,用什么 一种简单的编码纪律!”


当前回答

我避免使用它,因为同事/经理无疑会在代码评审或偶然发现它时质疑它的使用。虽然我认为它有一些用途(例如错误处理案例),但你会遇到一些其他开发人员,他们会遇到一些类型的问题。

这不值得。

其他回答

我避免使用它,因为同事/经理无疑会在代码评审或偶然发现它时质疑它的使用。虽然我认为它有一些用途(例如错误处理案例),但你会遇到一些其他开发人员,他们会遇到一些类型的问题。

这不值得。

后藤认为他很有帮助。

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

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

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

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

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

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

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

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

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

有时候,在一个函数中使用GOTO作为异常处理的替代是有效的:

    if (f() == false) goto err_cleanup;
    if (g() == false) goto err_cleanup;
    if (h() == false) goto err_cleanup;
    
    return;
    
    err_cleanup:
    ...

COM代码似乎经常陷入这种模式。

从这里的任何答案中我都没有看到的一件事是,“去”解决方案通常比经常提到的结构化编程解决方案更有效。

考虑多嵌套循环的情况,其中使用'goto'而不是一堆if(breakVariable)节显然更有效。“将循环放入函数并使用return”的解决方案通常是完全不合理的。在循环可能使用局部变量的情况下,现在必须通过函数参数传递它们,可能会处理由此产生的额外麻烦。

现在考虑一下清理情况,我自己经常使用这种情况,而且这种情况非常常见,可能是try{} catch{}结构在许多语言中都不可用的原因。完成相同任务所需的检查和额外变量的数量远比完成跳转所需的一两个指令要糟糕得多,而且,额外的函数解决方案根本不是解决方案。你不能告诉我这更容易管理或更易于阅读。

现在,代码空间、堆栈使用和执行时间在许多情况下对许多程序员来说可能还不够重要,但当您在一个只有2KB代码空间的嵌入式环境中工作时,为了避免一个明确定义的“goto”而额外执行50字节的指令是可笑的,而且这种情况并不像许多高级程序员所认为的那样罕见。

“goto有害”这句话对迈向结构化编程非常有帮助,即使它总是一种过度概括。在这一点上,我们都听到了足够多的使用它的谨慎(我们应该)。当它显然是工作的正确工具时,我们不需要害怕它。

我只记得用过一次goto。我有一系列五个嵌套计数循环,我需要能够根据某些条件从内部打破整个结构:

    for{
      for{
        for{
          for{
            for{
              if(stuff){
                GOTO ENDOFLOOPS;
              }
            }
          }
        }
      }
    }
    
    ENDOFLOOPS:

我可以很容易地声明一个布尔中断变量,并将其用作每个循环的条件的一部分,但在这种情况下,我认为GOTO是一样实用和一样可读的。

没有迅猛龙攻击我。