【问题标题】:good c style when checking lots of return values检查大量返回值时的良好 c 风格
【发布时间】:2010-03-09 18:51:03
【问题描述】:

有时我必须编写在执行操作和检查错误条件之间交替的代码(例如,调用库函数,检查其返回值,继续执行)。这通常会导致长时间运行,实际工作在 if 语句的条件下发生,例如

if(! (data = (big_struct *) malloc(sizeof(*data)))){
    //report allocation error
} else if(init_big_struct(data)){
    //handle initialization error
} else ...

你们是如何编写这种代码的?我查看了一些样式指南,但它们似乎更关心变量命名和空格。

欢迎提供风格指南的链接。

编辑:如果不清楚,我对这种风格的易读性不满意,正在寻找更好的东西。

【问题讨论】:

  • 当您使用它时,我个人会放弃 (big_struct *) 演员表,除非您需要使用 C++ 编译器来编译此代码。这是一个有争议的问题,但如果您没有任何 C++ 要求,我认为最好不要这样做。

标签: c coding-style


【解决方案1】:

虽然说起来让我很痛苦,但这可能是不受欢迎的goto 的情况。这是我在该主题上找到的一个链接:http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

【讨论】:

  • 如果您不愿意在代码中看到goto,您可以随时伪装它。 stackoverflow.com/questions/2314066/do-whilefalse
  • +1 使用 goto 仍然是这种可怕语言的最佳方式。
  • 是的 - 这是 C 代码的好习惯(在 c++ 代码中使用异常和 RAII)。将资源ptrs设置为NULL;当得到时设置然后有一个共同的退出点,如果!NULL则释放。唯一的缺点是它确实让你将所有资源变量放在函数的顶级范围内(我更喜欢尽可能在本地声明)
【解决方案2】:

我通常这样写代码:

data = (big_struct *) malloc(sizeof(*data));
if(!data){
    //report allocation error
    return ...;
}

err = init_big_struct(data);
if(err){
    //handle initialization error
    return ...;
}

...

这样我就避免了在 if 内部调用函数,并且调试更容易,因为你可以检查返回值。

【讨论】:

    【解决方案3】:

    不要在生产代码中使用assert。
    在调试模式下,assert 不应该用于实际可能发生的事情(比如malloc 返回NULL),而应该在不可能的情况下使用(比如数组索引在C 中超出范围)

    Read this post for more.

    【讨论】:

      【解决方案4】:

      我用过的一个效果很好的方法是 W. Richard Stevens 在Unix Network Programming 中使用的方法(代码可下载here。对于他一直希望成功的常用功能,并且没有追索权失败,他用大写字母(代码垂直压缩)包装它们:

      void * Malloc(size_t size) {
          void    *ptr;
          if ( (ptr = malloc(size)) == NULL)
              err_sys("malloc error");
          return(ptr);
      }
      

      err_sys 此处显示错误,然后执行exit(1)。这样你就可以调用 Malloc 并且知道如果有问题它会出错。

      UNP 仍然是我所拥有的唯一一本书,我认为作者的代码可以检查所有可能失败的函数的返回值。其他每一本书都说“你应该检查返回值,但我们会把它留给你以后做”。

      【讨论】:

      • 应该注意的是,虽然这样的解决方案通常对独立程序有好处,但在库中以这种方式处理错误是非常糟糕的主意——它们永远不应该意外中止。
      【解决方案5】:

      我倾向于

      • 将错误检查委托给包装函数(如 Stevens)
      • 出错时,使用longjmp 模拟异常。 (我实际上使用 Dave Hanson 的 C Interfaces and Implementations 来模拟异常。)

      另一种选择是使用 Don Knuth 的 literate programming 来管理错误处理代码或其他类型的预处理器。仅当您为商店设置规则时,此选项才可用:-)

      【讨论】:

        【解决方案6】:

        像这样的代码的唯一分组属性是它必须遵循一个外部强加的顺序。这就是为什么将这些分配放在一个函数中的原因,但这是一个非常弱的共性。为什么有些人建议放弃嵌套 if 的范围优势超出了我的理解。您实际上是在尝试给猪涂口红(无意侮辱)-代码的性质永远不会产生任何干净的东西,您能做的最好的事情就是使用编译器帮助捕获(维护)错误。坚持 if 的恕我直言。

        PS:如果我还没有说服你:如果你必须做出三元决策,那么 goto 解决方案会是什么样子? if 肯定会变得更丑,但是 goto 呢???

        【讨论】:

          猜你喜欢
          • 2016-04-25
          • 1970-01-01
          • 2016-11-10
          • 2016-07-17
          • 1970-01-01
          • 2011-01-27
          • 1970-01-01
          • 2011-02-11
          • 2010-10-18
          相关资源
          最近更新 更多