我一直有一个印象,如果可能的话,永远不要使用goto。
然而,在前几天阅读libavcodec(它是用C编写的)时,我惊讶地注意到它的多种用法。
在支持循环和函数的语言中使用goto是否有优势?如果有,为什么?请提供一个具体的例子,清楚地说明使用goto的理由。
我一直有一个印象,如果可能的话,永远不要使用goto。
然而,在前几天阅读libavcodec(它是用C编写的)时,我惊讶地注意到它的多种用法。
在支持循环和函数的语言中使用goto是否有优势?如果有,为什么?请提供一个具体的例子,清楚地说明使用goto的理由。
当前回答
在c#中,switch语句不允许切换。因此,goto用于将控制转移到特定的开关箱标签或默认标签。
例如:
switch(value)
{
case 0:
Console.WriteLine("In case 0");
goto case 1;
case 1:
Console.WriteLine("In case 1");
goto case 2;
case 2:
Console.WriteLine("In case 2");
goto default;
default:
Console.WriteLine("In default");
break;
}
编辑:有一个例外的“不掉落”规则。如果case语句没有代码,则允许延迟执行。
其他回答
我遇到过goto是一个很好的解决方案的情况,我在这里或其他地方都没有看到过这个例子。
我有一个开关的情况下,所有的情况都需要调用相同的函数在最后。我有其他的情况,最后都需要调用不同的函数。
这看起来有点像这样:
switch( x ) {
case 1: case1() ; doStuffFor123() ; break ;
case 2: case2() ; doStuffFor123() ; break ;
case 3: case3() ; doStuffFor123() ; break ;
case 4: case4() ; doStuffFor456() ; break ;
case 5: case5() ; doStuffFor456() ; break ;
case 6: case6() ; doStuffFor456() ; break ;
case 7: case7() ; doStuffFor789() ; break ;
case 8: case8() ; doStuffFor789() ; break ;
case 9: case9() ; doStuffFor789() ; break ;
}
我没有给每个case一个函数调用,而是用goto代替了break。goto跳转到一个标签,这也是在开关的情况下。
switch( x ) {
case 1: case1() ; goto stuff123 ;
case 2: case2() ; goto stuff123 ;
case 3: case3() ; goto stuff123 ;
case 4: case4() ; goto stuff456 ;
case 5: case5() ; goto stuff456 ;
case 6: case6() ; goto stuff456 ;
case 7: case7() ; goto stuff789 ;
case 8: case8() ; goto stuff789 ;
case 9: case9() ; goto stuff789 ;
stuff123: doStuffFor123() ; break ;
stuff456: doStuffFor456() ; break ;
stuff789: doStuffFor789() ; break ;
}
案例1到3都必须调用doStuffFor123(),类似的案例4到6必须调用doStuffFor456()等。
在我看来,如果你正确使用它们,gotos是非常好的。最后,任何代码都像人们写的那样清晰。有了gotos,你可以写出意大利面代码,但这并不意味着gotos是意大利面代码的原因。这个事业就是我们;程序员。如果我愿意,我也可以用函数创建意大利面条代码。宏也是如此。
我发现do{} while(false)的用法完全令人反感。它可能会让我相信它在某些奇怪的情况下是必要的,但从来没有让我相信它是干净合理的代码。
如果必须执行这样的循环,为什么不显式地依赖标志变量呢?
for (stepfailed=0 ; ! stepfailed ; /*empty*/)
使用“goto”使你的代码更易于阅读或运行得更快。只是不要让它把你的代码变成意大利面条。
在c#中,switch语句不允许切换。因此,goto用于将控制转移到特定的开关箱标签或默认标签。
例如:
switch(value)
{
case 0:
Console.WriteLine("In case 0");
goto case 1;
case 1:
Console.WriteLine("In case 1");
goto case 2;
case 2:
Console.WriteLine("In case 2");
goto default;
default:
Console.WriteLine("In default");
break;
}
编辑:有一个例外的“不掉落”规则。如果case语句没有代码,则允许延迟执行。
关于goto语句,它们的合法用途,以及可以用来代替“有道德的goto语句”但也可以像goto语句一样容易被滥用的替代结构,最深思熟虑和彻底的讨论是Donald Knuth的文章“使用goto语句的结构化编程”,在1974年12月的Computing Surveys(卷6,no. 1)中。4. 第261 - 301页)。
毫不奇怪,这篇39年前的论文的某些方面已经过时了:处理能力的数量级增长使得Knuth的一些性能改进对于中等规模的问题来说并不明显,从那时起就发明了新的编程语言结构。(例如,try-catch块包含Zahn的Construct,尽管它们很少以这种方式使用。)但Knuth涵盖了争论的方方面面,在任何人再次重复这个问题之前,都应该要求阅读。