C代码中的错误处理

C代码中的错误处理

在C库中以一致的方式处理错误处理错误时,您认为“最佳实践”是什么?

我一直在考虑两种方式:

始终返回错误代码。典型的功能如下所示:

MYAPI_ERROR getObjectSize(MYAPIHandle h, int* returnedSize);

始终提供错误指针方法:

int getObjectSize(MYAPIHandle h, MYAPI_ERROR* returnedError);

使用第一种方法时,可以编写这样的代码,其中错误处理检查直接放在函数调用上:

int size;if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
  // Error handling}

这看起来比错误处理代码更好。

MYAPIError error;int size;size = getObjectSize(h, &error);if(error != MYAPI_SUCCESS) {
    // Error handling}

但是,我认为使用返回值返回数据会使代码更具可读性。很明显,在第二个示例中,某些内容被写入了size变量。

您对我为什么应该选择这些方法或者将它们混合或使用其他方法有任何想法吗?我不是全局错误状态的粉丝,因为它往往会使库的多线程使用更加痛苦。

编辑:只要他们不涉及异常,C ++关于此的具体想法也会很有趣,因为目前我不能选择...


牛魔王的故事
浏览 535回答 3
3回答

幕布斯6054654

我喜欢错误作为返回值方式。如果您正在设计api并且想要尽可能轻松地使用您的库,请考虑以下添加:将所有可能的错误状态存储在一个typedef'ed枚举中,并在lib中使用它。不要只返回整数或更糟,混合整数或不同的枚举与返回代码。提供将错误转换为人类可读的东西的功能。可以很简单。只是错误枚举,const char * out。我知道这个想法使多线程使用有点困难,但如果应用程序员可以设置全局错误回调那就太好了。这样他们就可以在bug追捕会话期间将断点放入回调中。希望能帮助到你。

茅侃侃

我已经使用了这两种方法,它们对我来说都很好。无论我使用哪一个,我总是尝试应用这个原则:如果唯一可能的错误是程序员错误,请不要返回错误代码,在函数内部使用断言。验证输入的断言清楚地传达了函数所期望的内容,而过多的错误检查会使程序逻辑模糊不清。决定如何处理所有各种错误情况可能会使设计复杂化。为什么要弄清楚函数X应该如何处理空指针,如果你可以坚持程序员永远不会传递一个?

白板的微信

CMU的CERT 有一套很好的幻灯片,建议何时使用每种常见的C(和C ++)错误处理技术。最佳幻灯片之一是这个决策树:我会亲自改变关于这款跑车的两件事。首先,我要澄清有时对象应该使用返回值来指示错误。如果函数仅从对象中提取数据但不改变对象,则对象本身的完整性不存在风险,并且使用返回值指示错误更合适。其次,在C ++中使用异常并不总是合适的。异常是好的,因为它们可以减少用于错误处理的源代码量,它们通常不会影响函数签名,并且它们可以非常灵活地传递callstack的数据。另一方面,由于以下几个原因,异常可能不是正确的选择:C ++异常具有非常特殊的语义。如果你不想要那些语义,那么C ++异常是一个糟糕的选择。抛出后必须立即处理异常,并且设计有利于错误需要将调用堆栈展开几个级别。抛出异常的C ++函数以后不会被包装成不抛出异常,至少在没有支付异常的全部代价的情况下也是如此。可以包含返回错误代码的函数以抛出C ++异常,从而使它们更加灵活。C ++ new通过提供非投掷变体来实现这一目标。C ++异常相对较为昂贵,但这种缺点主要是对于合理使用异常的程序而言过于夸张。程序根本不应该在性能受到关注的代码路径上抛出异常。程序报告错误和退出的速度并不重要。有时C ++异常不可用。要么它们在一个人的C ++实现中根本不可用,要么一个代码指南禁止它们。由于最初的问题是关于多线程的上下文,我认为本地错误指示器技术(在SirDarius的答案中描述的内容)在原始答案中被低估了。它是线程安全的,不会强制错误被调用者立即处理,并且可以捆绑描述错误的任意数据。缺点是它必须由一个对象保持(或者我想以某种方式与外部相关联)并且可以说比返回代码更容易被忽略。
打开App,查看更多内容
随时随地看视频慕课网APP