【问题标题】:What's the most appropriate way to handle errors in C? [closed]处理 C 中的错误的最合适方法是什么? [关闭]
【发布时间】:2022-01-13 17:50:53
【问题描述】:

我最近一直在提高我的 C 编程能力,但我遇到了如何最好地处理错误的问题。我目前的方法是为给定的操作定义一些错误enum,例如:

typedef struct {
  err_not_an_error=0,
  err2,
  err3,
  ...
} error_class_err_t

并且让该操作的所有函数返回 error_class,通过引用返回它们的值,例如 error_class_err_t function(return_type* return,...)

这将涉及调用函数:

return_type output;
if (err=function(&output,...))
  handle_error(err);

这适用于单个错误类,但对于多个错误类变得相当麻烦。我很好奇这种功能的最佳模式是什么。

【问题讨论】:

  • 为什么需要多个错误类?我问是因为这相当接近行业标准方法,并且您拥有多个课程的意图可能在答案中发挥了不错的作用。您是否正在考虑同一个库中的 2 个函数返回不同的错误,或者您是否正在考虑像 C++ 异常一样的错误层次结构
  • returning their value by reference, e.g., error_class_err_t function... 嗯,这不是参考。这是价值回报。
  • @CortAmmon 好吧,如果我有多个库有不同的错误,你会想要区分不同的错误类型,除非我误解了
  • @KamilCuk 我指的是使用output,而不是错误代码,我很抱歉。

标签: c error-handling


【解决方案1】:

我在业界看到的典型做法是,每个库都使用所有可能的错误代码的并集构造一个枚举,然后使用它。 POSIX 就是一个很好的例子。 POSIX 中的许多错误对于任何给定的函数都没有意义,但它们在同一个枚举中(或者,在他们的情况下,是一个宏)。

我已经看到一些将错误整数的空间划分为区域(例如 100、200 等或 2 的幂),并提供了一种方法来讨论在驱动到实际错误之前发生的错误类别.

【讨论】:

  • 你能有一个我可以看的例子的链接吗?
  • 老实说,拉起一个大型 C API,你会发现它。副手,POSIX、Java 的 JVM、Python 的 C API、Windows API 都浮现在脑海中。我见过的规则的唯一例外是那些使用 errno 的例外。我随机选择了Bonjour,作为我知道有一个C API 的库,查找了它的头文件,发现它使用了它。 (枚举从该文件的第 644 行开始)
【解决方案2】:

在 C 中处理错误最合适的方法是什么?

没有一般意义上的“最合适”。它与您正在编写的特定任务和库高度相关。

例如对于您的特定案例:

这适用于单个错误类,但对于多个错误类变得相当麻烦。

使用位对错误类进行编码,例如:

enum {
 ERROR_HW  = 0x8000,
 ERROR_SPI = 0x4000,
 ERROR_I2C = 0x2000,
};

typedef enum {
  OK=0,
  err1 = ERROR_HW | 1, /* class with error */
  err2 = ERROR_HW | ERROR_SPI | 2, /* error can be in multiple classes */
  err3 = ERROR_I2C | 3,
  err4 = ERROR_HW | ERROR_I2C | 4,
  /* etc. just an example of values */
} error_class_err_t;

static inline bool IS_HW_ERROR(error_class_err_t x) {
    return x & ERROR_HW;
}
/* etc. */

int main() {
  data output;
  error_class_err_t err = function(&output,...);
  if (err) {
    if (IS_HW_ERROR(err)) {
       fix_hw();
    } /* etc. */
  }
}

请注意,例如在使用 < > 时,enum 类型可能已签名 - 为了安全起见,您可以强制转换为 unsinged

从 MBed OS 错误处理中汲取灵感:https://os.mbed.com/docs/mbed-os/v6.15/apis/error-handling.htmlhttps://github.com/ARMmbed/mbed-os/blob/a3be10c976c36da222517abc0cb4f81e88ff8552/platform/include/platform/mbed_error.h#L71

【讨论】:

    【解决方案3】:

    试试函数 errno() perror() strerror()。 有关man page 的更多信息。

    【讨论】:

      【解决方案4】:
      typedef struct {
        OK=0,
        err1 = 1,
        err2 = 2,
        err3 = 4,
        err4 = 8
        ...
      } error_class_err_t
      

      然后对错误进行逻辑或。这应该允许在现代 PC 上出现 64 个不同的错误。

      【讨论】:

      • 这不一定能解决我遇到的问题,假设我有与树结构使用的链表结构相对应的错误,我将如何最好地将链表错误与树错误?
      • @user852541 听起来好像我不太明白你原来的问题。我设想树说“我没有按照你的要求做,因为链表返回了错误”。在您的示例中,您是否设想树中有几个地方可能会发生这种情况,以及几个可能的列表错误?
      猜你喜欢
      • 1970-01-01
      • 2014-03-12
      • 2017-11-13
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 2015-06-12
      • 2017-12-26
      相关资源
      最近更新 更多