而(1)..打破,而不是转到(while(1) .. break instead of goto)

2019-06-24 18:26发布

我发现在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不回答我的问题。

Answer 1:

看似普遍revultion到GOTO很大程度上是由于Edsger Dijkstra的字母“goto语句是有害的”。

如果你坚决不使用goto语句,像

do {
    ...
while(0);

可能比同时更安全(1){...},因为它保证你不会在不经意间循环(如果你无意中循环,有一段时间(1)你可能无意中无限循环)。

即(AB)使用做的一个好处/休息/ while或同时/为此,打破了在后藤是,你保证不会被构建上面跳-后藤可用于在同一较早跳转到一个标签功能。

那些/休息/而等有超过转到缺点是,你是有限的(循环后)一个出口点。 在某些情况下,你可能需要分阶段清理:例如,当你打开一个文件句柄,malloc的一些记忆,从文件中读取...如果读取失败,你需要清理的malloc。 如果malloc的失败,你不需要把它清理干净,但你仍然需要清理的文件句柄。 随着跳转,你可以为每个清理阶段一个标签,并跳转到恰到好处的点取决于你发生错误的位置。

在我看来,一味地回避,因为普遍的仇恨GOTO它比仔细推理出的情况下,其对案件逐案基础上使用更具破坏性。 我使用的经验法则是“不Linux内核做呢?如果是的话,就不能不好”。 替换Linux内核与现代软件工程的任何其他很好的例子。



Answer 2:

把代码放到一个单独的函数,用return提前退出是另一种方式来做到这一点,可轻松集成的指示故障的性质返回代码的好处。



Answer 3:

虽然使用goto通常气馁,像你这样的一些罕见的情况下,是一个地方,最好的做法是不是最好的。

所以,如果转到使得清晰的代码,我会用它。 使用while(true)循环来模拟转到东西不自然。 你真正需要的是一个goto!



Answer 4:

我知道我的风格是不是最酷的可能,但我更喜欢它,因为它不需要任何特殊的结构和简洁并不难懂:

error = (!error) && do_something1();
error = (!error) && do_something2();
error = (!error) && do_something3();

// Cleanup code


Answer 5:

为什么不使用一系列的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可能被禁止的,但往往等都是breakcontinue如此循环不一定是一个解决办法。



Answer 6:

“中断”理解块范围的语义,而“GOTO”是无视它。 换言之,“而通断”可以被翻译成的语言的功能等与尾递归LISP,“GOTO”不能。



Answer 7:

通常情况下,GOTO语句被认为是不好的,但在一些地方,只有向前跳转通过GOTO语句,它们是不是那么糟糕。 人们避免GOTO像瘟疫而是一个深思熟虑的停止使用GOTO有时是更好的解决方案恕我直言。



Answer 8:

我认为,这种跳转的使用(资源管理)是确定的。



Answer 9:

使用它,如果你不能使用goto无论出于何种原因

  • 禁止在项目的约定
  • 通过您的皮棉工具禁止

我也觉得也是其中宏不是邪恶的情况之一:

#define DO_ONCE for (int _once_dummy = 0; _once_dummy < 1; _once_dummy++)


Answer 10:

我喜欢的,而(1)的方式。 我用它自己。 特别是,当循环可能通过继续,如得到重复,当元件被这样的循环中进行处理,而且它在多种方法来完成。



Answer 11:

切勿使用条件与循环永久的真实情况。 由于条件总是真的,为什么使用条件循环?

永久真实情况是由一个goto最直接的表示。



Answer 12:

当使用“转到”用于错误处理的情况是相当普遍的,我还是比较喜欢“而”解决方案(或“做,而”)。 在“转到”的情况下,也有少得多的东西,编译器可以保证。 如果您在标签名称的拼写错误,编译器不能帮助你。 如果有人使用另一个转到另一个标签在该块,有一个很好的机会,清理代码不会被调用。 当您使用更加结构化的流程控制结构,你总是保证该代码将运行一次的循环已经结束。



Answer 13:

“而做”和“转到了”是对这些区域的不同:

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
标签: c goto