我在C程序中找到了以下代码:
while (1)
{
do_something();
if (was_an_error()) break;
do_something_else();
if (was_an_error()) break;
[...]
break;
}
[cleanup code]
Run Code Online (Sandbox Code Playgroud)
这里while(1)用作"终于"的本地模拟.你也可以用gotos 写这个:
do_something()
if (was_an_error()) goto out;
do_something_else()
if (was_an_error()) goto out;
[...]
out:
[cleanup code]
Run Code Online (Sandbox Code Playgroud)
我认为goto解决方案是一种常用的习惯用法.我在内核源代码中看到过几次这种习惯用法,在Diomidis Spinellis的"代码阅读"一书中也提到过.
我的问题是:什么解决方案更好?有没有具体的理由使用该while(1)解决方案?
问题943826没有回答我的问题.
jmt*_*mtd 33
对GOTO的看似普遍的反驳很大程度上归功于Edsger Dijkstra的信"Go To Statement Considered Harmful".
如果你决定不使用goto,那就像
do {
...
while(0);
Run Code Online (Sandbox Code Playgroud)
可能比(1){...}更安全,因为它保证你不会无意中循环(如果你无意中循环,而while(1)你可能无意中无限循环).
即(AB)使用做的一个好处/休息/ while或同时/为此,打破了在后藤是,你保证不会是跳跃上面的构造- goto语句可以用来在同一较早跳转到一个标签功能.
do/break/while等过度goto的缺点是你被限制在一个出口点(紧接在循环之后).在某些情况下,您可能需要进行分阶段清理:例如,当您打开文件句柄时,malloc一些内存,从文件中读取...如果读取失败,则需要清理malloc.如果malloc失败,您不需要清理它,但仍需要清理文件句柄.使用goto,每个清理阶段可以有一个标签,并根据错误发生的位置跳转到正确的点.
在我看来,由于对它的普遍仇恨而盲目地避免使用GOTO比在个案基础上仔细推理其使用案例更具破坏性.我使用的经验法则是"Linux内核是否做到了?如果是这样,它就不会那么糟糕".用任何其他现代软件工程的好例子替换linux内核.
我知道我的风格不是最酷的,但我更喜欢它,因为它不需要任何特殊的结构,而且简洁而且不太难理解:
error = (!error) && do_something1(); error = (!error) && do_something2(); error = (!error) && do_something3(); // Cleanup code
虽然通常不鼓励使用goto,但像你这样的一些罕见的情况是最好的做法不是最好的地方.
所以,如果goto制作最清晰的代码,我会使用它.使用while(true)循环来模拟goto是不自然的.你真正需要的是一个转到!
为什么不使用一系列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]
Run Code Online (Sandbox Code Playgroud)
此外,如果您正在努力达到严格的编码标准,goto可能会禁止使用yes ,但通常也是如此break,continue因此循环不一定是解决方法.
“do while”和“goto out”在这些方面是不同的:
1.局部变量初始化
void foo(bool t = false)
{
if (t)
{
goto DONE;
}
int a = 10; // error : Goto bypass local variable's initialization
cout << "a=" << a << "\n";
DONE:
}
Run Code Online (Sandbox Code Playgroud)
可以在 do ... while(0) 块中初始化就地局部变量。
void bar(bool t = false)
{
do{
if (t)
{
break;
}
int a = 10; // fine
cout << "a=" << a << "\n";
} while (0);
}
Run Code Online (Sandbox Code Playgroud)
宏的差异为 2。“do while”稍微好一些。宏中的“goto DONE”并非如此。如果退出代码更复杂,让我们看看这样:
err = some_func(...);
if (err)
{
register_err(err, __LINE__, __FUNC__);
#if defined (_DEBUG)
do_some_debug(err)
#endif
break;
}
Run Code Online (Sandbox Code Playgroud)
当你一次又一次地编写这些代码时,你可能会将它们放入宏中。
#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. \
}
Run Code Online (Sandbox Code Playgroud)
代码变成:
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);
Run Code Online (Sandbox Code Playgroud)
3.do...while(0) 使用同一宏处理不同级别的退出。代码如上所示。goto ... 宏则不然,因为不同级别需要不同的标签。
这么说来,我都不喜欢他们两个。我更喜欢使用异常方法。如果不允许异常,那么我使用“do ... while(0)”,因为整个块是缩进的,它实际上比“goto DONE”样式更容易阅读。
| 归档时间: |
|
| 查看次数: |
13422 次 |
| 最近记录: |