题
在这个线程中,我们看的例子很好用 goto
在C或C++。它的灵感来自于 一个答案 人们投票,因为他们以为我是在开玩笑。
摘要(签变化,从原来做的意图更清楚地):
infinite_loop:
// code goes here
goto infinite_loop;
为什么它比的备选方案:
- 这是具体的。
goto
是的 语言构建这会导致一个 无条件的支。替代品 取决于使用的结构 支持有条件的分支, 有个堕落的总-真的 条件。 - 标签的文件的意图 没有额外的评论。
- 阅读器没有扫描
干预代码,用于早期
break
s (虽然它仍然是可能的 没有原则黑客来模拟continue
与早期goto
).
规则:
- 假装gotophobes没有 赢。它的理解是,以上 不能够用于现实代码,因为 它违背既定惯用语。
- 假设我们已经听到的 'Goto认为是有害的',并知道 那转到可以用来写 意大利面条码。
- 如果您不同意的一个实例, 批评它对技术优点 单(',因为人们不喜欢 转到'不是一个技术上的原因).
让我们看看如果我们可以谈谈这个像大人。
编辑
这个问题似乎完成。它产生了一些高质量的答复。感谢每一个人,
尤其是那些把我的小循环的例子严重。大多数怀疑者被关注
由于缺乏框范围。作为@quinmars指出的评论,你总是可以把括号围
循环体。我注意到在通过, for(;;)
和 while(true)
不会给你的牙套
免费者(和忽略他们可能会导致令人烦恼的bug).无论如何我不会浪费任何更多的
你的大脑能力在这种小事一桩-我可以接受的无害的,习惯 for(;;)
和 while(true)
(只因为如果我要保持我的工作)。
考虑到其他答复,我看到,许多人查看 goto
为什么你总是
必须重写的另一种方式。你当然可以避免 goto
通过引入一个循环,
一个额外的标志,堆叠的嵌套 if
s,或什么,但为什么不考虑是否 goto
是
也许最好的工具工作?把另一种方式,多么的丑陋的人准备承受的避免使用一个内置的语言功能用于其预期的目的是什么?我是
即使是加入一个标志是过高的价格支付。我喜欢我的变量来表示的东西在
问题或解决方案的领域。'完全避免 goto
'不削减它。
我会接受第一个回答给C模式的分支到清理的区块。海事组织,这使最强的情况下,对于一个 goto
所有发表的答复,肯定
如果你测量它的憎恨的扭曲已经通过,以避免它。
解决方案
下面有一个魔术我已经听说过的人使用。我从来没有见过它在野外。它只适用于C,因为C++已RAII要做到这更多的习惯用法.
void foo()
{
if (!doA())
goto exit;
if (!doB())
goto cleanupA;
if (!doC())
goto cleanupB;
/* everything has succeeded */
return;
cleanupB:
undoB();
cleanupA:
undoA();
exit:
return;
}
其他提示
经典的需要转到C如下
for ...
for ...
if(breakout_condition)
goto final;
final:
没有简单的方法来打破的嵌套的循环不goto.
这里是我不蠢如,(从史蒂文斯APITUE)Unix系统调用其可以中断一个信号。
restart:
if (system_call() == -1) {
if (errno == EINTR) goto restart;
// handle real errors
}
替代性是一种退化循环。这个版本英文读起来就像"如果系统通话中断了信号,重新启动它的"。
如果达芙的设备不需要goto,然后你也不应该!;)
void dsend(int count) {
int n;
if (!count) return;
n = (count + 7) / 8;
switch (count % 8) {
case 0: do { puts("case 0");
case 7: puts("case 7");
case 6: puts("case 6");
case 5: puts("case 5");
case 4: puts("case 4");
case 3: puts("case 3");
case 2: puts("case 2");
case 1: puts("case 1");
} while (--n > 0);
}
}
代码以上,从维基百科 项.
Knuth写了文件"的结构编程与转到的声明",可以获得例如它从 在这里,.你会找到很多例子。
很常见的。
do_stuff(thingy) {
lock(thingy);
foo;
if (foo failed) {
status = -EFOO;
goto OUT;
}
bar;
if (bar failed) {
status = -EBAR;
goto OUT;
}
do_stuff_to(thingy);
OUT:
unlock(thingy);
return status;
}
唯一的情况下我没有用 goto
是跳转发,通常是出块,并且从来没有成块。这样可以避免滥用 do{}while(0)
和其他结构增加了筑巢,同时仍保持易读、结构化的代码。
我什么都没有对goto语句在一般情况下,但我可以想到的几个原因,为什么你不会想使用它们用于一个环喜欢你提到:
- 它不限制范围,因此任何临时变量使用内部不会被释放到以后。
- 它不限制范围,因此它可能导致错误。
- 它不限制范围,因此不能重新使用相同的变量名称后在未来的码在同一范围。
- 它不限制范围,因此你有机会的跳过一个可变的宣言》。
- 人们不习惯它,它会使你的代码的更难于阅读。
- 嵌套循环的这种类型可能导致意大利代码,法的循环将不会导致意大利代码。
一个很好的地方使用goto是在一个程序,可以中止在几个点,每个需要各级的清理。Gotophobes总是可以代替goto语句的用结构化码和一系列的试验,但我认为这是更简单,因为它消除了过多的压痕:
if (!openDataFile()) goto quit; if (!getDataFromFile()) goto closeFileAndQuit; if (!allocateSomeResources) goto freeResourcesAndQuit; // Do more work here.... freeResourcesAndQuit: // free resources closeFileAndQuit: // close file quit: // quit!
@fizzer.myopenid.com:你的代码贴段等同于以下列表的内容:
while (system_call() == -1)
{
if (errno != EINTR)
{
// handle real errors
break;
}
}
我绝对喜欢这的形式。
即使我已经长大恨这一模式随着时间的推移,它们在细的成COM编程。
#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
HRESULT hr = S_OK;
IfFailGo( pFoo->PerformAction() );
IfFailGo( pFoo->SomeOtherAction() );
Error:
return hr;
}
这里的一个例子是一个很好的转到:
// No Code
我已经看到正确使用,但情况是科丑陋的。只有当使用 goto
本身是如此少得多的比原来的。@森荷兰的麻烦了是你的版本是较不清楚。人们似乎害怕的地方变量:
void foo()
{
bool doAsuccess = doA();
bool doBsuccess = doAsuccess && doB();
bool doCsuccess = doBsuccess && doC();
if (!doCsuccess)
{
if (doBsuccess)
undoB();
if (doAsuccess)
undoA();
}
}
我更喜欢循环像这样但有些人喜欢 while(true)
.
for (;;)
{
//code goes here
}
我抱怨这是你失去框范围;任何地方的声明的变量之间的goto语句仍然有效,如果循环破裂出来的。(也许你是在假设运行循环永远;我不认为那是原来的问题的作家要求,虽然。)
问题的范围更是一个问题与C++、作为某些对象可以根据他们的dtor被称为在适当的时间。
对我来说,最好的理由使用转到的是在一个多步骤的初始化过程是至关重要的是,所有inits支持出,如果一个失败,la:
if(!foo_init())
goto bye;
if(!bar_init())
goto foo_bye;
if(!xyzzy_init())
goto bar_bye;
return TRUE;
bar_bye:
bar_terminate();
foo_bye:
foo_terminate();
bye:
return FALSE;
我不使用转到是我自己,但是我没有工作的人一旦将使用他们在特定的情况。如果我没有记错的话,他的理由是围绕性问题-他也有具体的规则 如何.总是在同样的功能,并标总是低于转发言。
#include <stdio.h>
#include <string.h>
int main()
{
char name[64];
char url[80]; /*The final url name with http://www..com*/
char *pName;
int x;
pName = name;
INPUT:
printf("\nWrite the name of a web page (Without www, http, .com) ");
gets(name);
for(x=0;x<=(strlen(name));x++)
if(*(pName+0) == '\0' || *(pName+x) == ' ')
{
printf("Name blank or with spaces!");
getch();
system("cls");
goto INPUT;
}
strcpy(url,"http://www.");
strcat(url,name);
strcat(url,".com");
printf("%s",url);
return(0);
}
@格雷格:
为什么不做你的例子是这样的:
void foo()
{
if (doA())
{
if (doB())
{
if (!doC())
{
UndoA();
UndoB();
}
}
else
{
UndoA();
}
}
return;
}