C 语言如何不用 goto、多处 return 进行错误处理?

我大概知道为什么会有这种规定了,单处 return 加禁止 goto,等于要求写这样的代码:

void foobar() {
    void* a  0, b  0, c  0;

    do {
        a = createA();
        if (!a) break;

        b = createB();
        if (!b) break;

        c = createC();
        if (!c) break;

        //...
    } while (0);

    if (c) freeC(c);
    if (b) freeB(b);
    if (a) freeA(a);
}

这样写倒也不是不行,就是凭空多了一个缩进,怪别扭的。

---- 分割线 ----

我至今不知道谁先发明了不允许多处 return 这种规定的,动机是什么。

是为了利于调试?增加可读性?这很有效吗?除非你在没有单步调试器的环境下,纯靠加代码打 log,单进单出可能有点意义。是为了释放资源吗?那么请看最后一段。

不允许多处 return 有一个显而易见的坏处,它会明显增加代码的缩进层次,我相信写过 c/c++ 或者 php、js 这类类 c 语言的同学都会有感觉。手机码字不方便,明天我会给出一个简单的例子。

另外在很多情况下,你必须使用很奇怪的流程才能实现单处 return,这样增加了思考成本不说,反而降低了代码的可读性。

所以我的建议是,能 return 就 return,能早 return 绝不晚 return,能用 return 减少大括号层次,坚决用。这不仅是代码格式上的考虑,深层次的动机是,早 return 的写法让代码“逻辑块”变得更小(逻辑块位于 return 和 return 之间),逻辑更单纯,一段尽早 return 的代码,一定比最后 return 的代码更好懂,也更符合直觉。

每次看到有人为了最后一行 return,在循环中记录返回值,break,然后在循环体外 return,我都觉得纯属有病。

至于 goto,平时自然是不用为好,太难把控。但是在那种依次申请资源,其中一个失败后倒序释放资源的情况中,不用 goto 纯属给自己找麻烦。刚才有朋友在评论中说 c 语言单处 return 是为了资源释放,其实当你多次 return 发现 hold 不住的时候,就应该果断上 goto。如果规范实在不让用 goto,那就只能在 while 中用 break 跳出,在结尾处用挨个释放资源。只不过这样代码不好看。

编辑于 2016-10-19 17:14

Published

Category

Zhihu

Tags