让我们说我想写一个游戏(用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语句的正确方法,还是我应该避免使用它?
答案 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);
}