1

假设我想写一个游戏(用 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 语句的正确方法,还是我应该避免它?

4

6 回答 6

6

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

C 提供了可无限滥用的 goto 语句和分支到的标签。形式上,goto 语句从来都不是必需的,实际上,没有它几乎总是很容易编写代码。在本书中我们没有使用 goto。然而,在某些情况下 goto 可能会找到一席之地。最常见的是放弃一些深度嵌套结构中的处理,例如一次跳出两个或多个循环。break 语句不能直接使用,因为它只从最内层循环退出。因此:

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

如果错误处理代码很重要,并且如果错误可能在多个地方发生,则这种组织很方便。

于 2013-02-27T12:26:26.703 回答
4

通常,使用 C 的人讨厌 goto,因为他们认为“摆脱对 goto 的需求”是开始使用 C 的原因之一。

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

我会完全避免 gotos 。

事实上,我使用 goto 的唯一原因是,当我想在编写需要用汇编编写的赋值程序之前用 C 编写程序时(使用 goto 更容易可视化)。

在任何情况下,如果您觉得使用 goto 对“正常”控制语句有好处,请继续使用它们。但请注意,有龙。

于 2013-02-27T12:25:52.437 回答
4

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

我想说第一个更清楚易懂。

于 2013-02-27T12:28:15.230 回答
3

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

于 2013-02-27T12:31:40.683 回答
3

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

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

有些人认为 goto 被认为是有害的,在任何情况下都不应使用,因为 goto 关键字总是可以被其他语言机制替换。

就个人而言,我更喜欢从不使用 goto,主要是为了避免争论,但我使用了一个非常相似的结构,具有以下功能:

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

bool play_a_game (void)
{
  game();      

  return play_again();
}

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

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

于 2013-02-27T12:39:49.423 回答
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);
}        
于 2013-02-27T12:34:25.603 回答