我发现在C程序下面的代码:
while (1)
{
do_something();
if (was_an_error()) break;
do_something_else();
if (was_an_error()) break;
[...]
break;
}
[cleanup code]
在这里while(1)
被用作“终于”本地仿真。 你也可以这样写使用goto
S:
do_something()
if (was_an_error()) goto out;
do_something_else()
if (was_an_error()) goto out;
[...]
out:
[cleanup code]
我以为转到解决方案是一个常用的成语。 我已经看到了这成语的内核源代码的几次出现,它也被迪米迪斯·斯皮内利斯‘读码’书中提到。
我的问题是:什么解决方案是更好? 有没有使用任何特定的原因while(1)
解决方案?
问943826不回答我的问题。
看似普遍revultion到GOTO很大程度上是由于Edsger Dijkstra的字母“goto语句是有害的”。
如果你坚决不使用goto语句,像
do {
...
while(0);
可能比同时更安全(1){...},因为它保证你不会在不经意间循环(如果你无意中循环,有一段时间(1)你可能无意中无限循环)。
即(AB)使用做的一个好处/休息/ while或同时/为此,打破了在后藤是,你保证不会被构建上面跳-后藤可用于在同一较早跳转到一个标签功能。
那些/休息/而等有超过转到缺点是,你是有限的(循环后)一个出口点。 在某些情况下,你可能需要分阶段清理:例如,当你打开一个文件句柄,malloc的一些记忆,从文件中读取...如果读取失败,你需要清理的malloc。 如果malloc的失败,你不需要把它清理干净,但你仍然需要清理的文件句柄。 随着跳转,你可以为每个清理阶段一个标签,并跳转到恰到好处的点取决于你发生错误的位置。
在我看来,一味地回避,因为普遍的仇恨GOTO它比仔细推理出的情况下,其对案件逐案基础上使用更具破坏性。 我使用的经验法则是“不Linux内核做呢?如果是的话,就不能说不好”。 替换Linux内核与现代软件工程的任何其他很好的例子。
把代码放到一个单独的函数,用return
提前退出是另一种方式来做到这一点,可轻松集成的指示故障的性质返回代码的好处。
虽然使用goto通常气馁,像你这样的一些罕见的情况下,是一个地方,最好的做法是不是最好的。
所以,如果转到使得清晰的代码,我会用它。 使用while(true)循环来模拟转到东西不自然。 你真正需要的是一个goto!
我知道我的风格是不是最酷的可能,但我更喜欢它,因为它不需要任何特殊的结构和简洁并不难懂:
error = (!error) && do_something1();
error = (!error) && do_something2();
error = (!error) && do_something3();
// Cleanup code
为什么不使用一系列的if
语句? 我通常把它写这样一来,因为我觉得它比一个循环更加清晰:
bool ok = true;
do_something();
if (was_an_error()) ok = false;
if (ok)
{
do_something_else();
if (was_an_error()) ok = false;
}
if (ok)
{
do_something_else_again();
if (was_an_error()) ok = false;
}
[...]
[Cleanup code]
此外,如果你正在严格的编码标准,是goto
可能被禁止的,但往往等都是break
和continue
如此循环不一定是一个解决办法。
“中断”理解块范围的语义,而“GOTO”是无视它。 换言之,“而通断”可以被翻译成的语言的功能等与尾递归LISP,“GOTO”不能。
通常情况下,GOTO语句被认为是不好的,但在一些地方,只有向前跳转通过GOTO语句,它们是不是那么糟糕。 人们避免GOTO像瘟疫而是一个深思熟虑的停止使用GOTO有时是更好的解决方案恕我直言。
使用它,如果你不能使用goto无论出于何种原因
我也觉得也是其中宏不是邪恶的情况之一:
#define DO_ONCE for (int _once_dummy = 0; _once_dummy < 1; _once_dummy++)
我喜欢的,而(1)的方式。 我用它自己。 特别是,当循环可能通过继续,如得到重复,当元件被这样的循环中进行处理,而且它在多种方法来完成。
切勿使用条件与循环永久的真实情况。 由于条件总是真的,为什么使用条件循环?
永久真实情况是由一个goto最直接的表示。
当使用“转到”用于错误处理的情况是相当普遍的,我还是比较喜欢“而”解决方案(或“做,而”)。 在“转到”的情况下,也有少得多的东西,编译器可以保证。 如果您在标签名称的拼写错误,编译器不能帮助你。 如果有人使用另一个转到另一个标签在该块,有一个很好的机会,清理代码不会被调用。 当您使用更加结构化的流程控制结构,你总是保证该代码将运行一次的循环已经结束。
“而做”和“转到了”是对这些区域的不同:
1.local变量初始化
void foo(bool t = false)
{
if (t)
{
goto DONE;
}
int a = 10; // error : Goto bypass local variable's initialization
cout << "a=" << a << "\n";
DONE:
}
它是好的初始化就地局部变量在做......而(0)块。
void bar(bool t = false)
{
do{
if (t)
{
break;
}
int a = 10; // fine
cout << "a=" << a << "\n";
} while (0);
}
2差为宏。 “做,而”轻微的更好。 “转到DONE”在宏是如此的情况并非如此。 如果退出代码是比较复杂的,我们看到这样的:
err = some_func(...);
if (err)
{
register_err(err, __LINE__, __FUNC__);
#if defined (_DEBUG)
do_some_debug(err)
#endif
break;
}
而你又写这个代码,并再次,你可能把它们放入一个宏。
#define QUIT_IF(err) \
if (err) \
{ \
register_err(err, __LINE__, __FUNC__); \
DO_SOME_DEBUG(err) \
break; // awful to put break in macro, but even worse to put "goto DONE" in macro. \
}
和代码变成:
do
{
initial();
do
{
err = do_step1();
QUIT_IF(err);
err = do_step2();
QUIT_IF(err);
err = do_step3();
QUIT_IF(err);
....
} while (0);
if (err) { // harder for "goto DONE" to get here while still using macro.
err = do_something_else();
}
QUIT_IF(err);
.....
} while (0);
3.do ......而(0)处理不同级别相同的宏退出的。 代码如上所示。 后藤......是不是你所需要的不同层次不同的标签宏观原因的情况。
按说,我不喜欢他们两个。 我更愿意使用异常的方法。 如果不允许例外,然后我用“做......而(0)”,因为整个块缩进,它实际上是比“转到DONE”的风格更容易阅读。
文章来源: while(1) .. break instead of goto