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


当前回答

实际上,我发现自己不得不使用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

其他回答

今天,很难看出GOTO语句有什么大不了的,因为“结构化编程”的人赢得了这场辩论,今天的语言有足够的控制流结构来避免GOTO。

计算现代C程序中goto的数量。现在添加break、continue和return语句的数量。此外,加上你使用if、else、while、switch或case的次数。这是1968年Dijkstra写这封信时,如果你用FORTRAN或BASIC语言编写程序,你的程序会有多少个goto。

当时的编程语言缺乏控制流程。例如,在最初的达特茅斯BASIC中:

IF statements had no ELSE. If you wanted one, you had to write: 100 IF NOT condition THEN GOTO 200 ...stuff to do if condition is true... 190 GOTO 300 200 REM else ...stuff to do if condition is false... 300 REM end if Even if your IF statement didn't need an ELSE, it was still limited to a single line, which usually consisted of a GOTO. There was no DO...LOOP statement. For non-FOR loops, you had to end the loop with an explicit GOTO or IF...GOTO back to the beginning. There was no SELECT CASE. You had to use ON...GOTO.

因此,您的程序中最终出现了许多goto。并且您不能依赖于goto限制在单个子例程中(因为GOSUB…RETURN是一个非常弱的子例程概念),所以这些goto可以去任何地方。显然,这使得控制流难以遵循。

这就是反goto运动的由来。

没有所谓的GOTO被认为是有害的。

GOTO是一种工具,和所有工具一样,它可以被使用和滥用。

然而,在编程世界中有许多工具倾向于被滥用而不是被使用,GOTO就是其中之一。Delphi的WITH语句是另一个。

就我个人而言,我在典型的代码中不使用这两种方法,但我有过GOTO和WITH的奇怪用法,这是有保证的,另一种解决方案将包含更多的代码。

最好的解决方案是编译器只警告你关键字被污染了,你必须在语句周围塞几个pragma指令来消除警告。

这就像告诉你的孩子不要拿着剪刀跑。剪刀并不坏,但使用它们可能不是保持健康的最佳方式。

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

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

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

没有迅猛龙攻击我。

几乎所有可以使用goto的情况,都可以使用其他结构实现相同的效果。无论如何,编译器都会使用Goto。

我个人从来没有明确地使用它,也不需要。

在Linux:在Kernel Trap的内核代码中使用goto,有一个与Linus Torvalds和一个“新人”关于在Linux代码中使用goto的讨论。有一些非常好的观点,莱纳斯穿着平常的傲慢:)

一些段落:

莱纳斯:不,你被洗脑了 国安局的人认为尼克劳斯 Wirth其实知道自己是什么 说什么。他没有。他不 我有个该死的线索。”

-

莱纳斯:“我觉得goto很好,而且 它们通常比 大量的压痕。”

-

莱纳斯:“当然,用愚蠢的语言 就像帕斯卡,在那里标签不能 描述性的,后去可能很糟糕。”