这是使用goto的可接受方式吗?

时间:2013-02-27 12:22:23

标签: c goto

让我们说我想写一个游戏(用C语言),询问用户在比赛结束后是否想再玩一次。

我看到两种明显的方法来写它。

首先:

int main(void)
{
    /* variable declarations and initializations */

    do { /* optionally multiple games */

        /* game code here */
        ........

        /* prompt user wheter he wants to play again */
        bool playagain = playagain();

    } while(playagain);

    .....
}

第二名:

int main(void)
{
    /* variable declarations and initializations */

game_start: /* optionally multiple games */

    /* game code here */
    ........

    /* prompt user wheter he wants to play again */
    bool playagain = playagain();

    if (playagain)
        goto game_start;

    .....
}

我知道通常使用goto语句是一个坏主意,但我认为这样可以使代码更清晰,并使我们免于额外的缩进级别。

所以我的问题是,这个特定的例子是否被认为是使用goto语句的正确方法,还是我应该避免使用它?

6 个答案:

答案 0 :(得分:6)

这不是更好的例子,在K& R中你可以找到一个好的例子:

  

C提供无限可滥用的goto语句,并标记为   分支到。形式上,goto语句永远不是必需的,并且在   在没有它的情况下编写代码几乎总是很容易。我们有   在本书中没有使用goto。然而,有一些情况   里奥斯可能找到一个地方。最常见的是放弃处理   在一些深层嵌套的结构中,例如突破两个或更多   一次循环。 break语句不能直接使用,因为它   只从最里面的循环退出。因此:

         for ( ... )
              for ( ... ) {
                  ...
                  if (disaster)
                       goto error;
              }
         ...
   error:
         /* clean up the mess */
     

如果错误处理代码非常重要,那么这个组织很方便,   如果在几个地方发生错误。

答案 1 :(得分:4)

一般来说,使用C的人讨厌搞砸,因为他们认为“远离需要的东西”是使用C开始的原因之一。

一旦您决定要使用gotos,请继续使用它们。但是一般情况下,它会导致令人困惑的代码,您将很难询问有关堆栈溢出的问题。

我完全避免搞砸了。

事实上,我使用gotos的唯一原因是我想在编写一个需要用汇编编写的赋值程序之前用C语言编写程序(用gotos更容易想象)。

在任何情况下,如果您觉得使用gotos比使用“普通”控制语句有好处,请继续使用它们。但要注意,有龙。

答案 2 :(得分:4)

在你的第二个例子中,你基本上是在编写一个循环,但不是使用现有的和众所周知的循环结构之一,而是使用if + goto。

我会说第一个更容易理解。

答案 3 :(得分:3)

我会使用第一个。如果它是最好的解决方案,使用goto并不是坏事。例如,如果我有两个嵌套的开关并希望从第一个中断第二个,我将使用goto而不是额外的变量和条件。你可以使用你喜欢的任何编码风格,但一般来说,我们避免使用它们,因为它们可以轻松搞乱我们的代码。但仍然是你的选择。

答案 4 :(得分:2)

经过40多年的辩论后,世界上所有程序员仍然没有达成共识。

最常见的意见(?)是在极少数情况下goto很好,在这种情况下它只应用于向下跳跃。一个这样的例子是打破多个测试的循环或语句。另一个例子是错误处理,你跳转到函数末尾的标签,“穷人的异常处理”。

有些人认为goto是considered harmful并且永远不会在任何情况下使用,因为goto关键字总是可以被其他语言机制替代。

我个人更喜欢不使用goto,主要是为了避免争论,而是使用一个非常相似的结构,带有函数:

int main()
{
  while (play_a_game())
    ;
}

bool play_a_game (void)
{
  game();      

  return play_again();
}

类似地,您可以使用函数的return语句而不是goto来中断多个循环。具有讽刺意味的是,C程序员很少遇到函数返回或break语句的问题,但是只要goto出现就会看到红色,即使生成的机器代码很可能是相同的。

根据经验:每当您担心多层缩进使代码无法读取时,函数始终是解决方案。

答案 5 :(得分:0)

我很少使用它作为“敲定”的方式。

fun () {
  d = getDatabaseConnection(...);
  if (d) {
    f = fopen(...);
    if (f) {
       ...do things...
       if (error(...)) {
         goto finalize;
       }
       ...do more things...
    }
  }

  finalize:
    if (f) fclose(f);
    if (d) closeDatabaseConnection(d);
}