Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C库中的错误报告_C_Design Patterns_Error Reporting - Fatal编程技术网

C库中的错误报告

C库中的错误报告,c,design-patterns,error-reporting,C,Design Patterns,Error Reporting,我正在寻找一种健壮的方法来报告C库中的错误。考虑队列的简单例子: struct queue *q = malloc(sizeof(*q)); if (NULL == q) { /* malloc failed. now what ? */ return NULL; /* maybe ? */ } 好的,对于这个例子来说,返回NULL在其他方面是无效的,所以返回它来表示错误是有意义的。但是 void *get_data() { /* stuff */ /* Er

我正在寻找一种健壮的方法来报告C库中的错误。考虑队列的简单例子:

struct queue *q = malloc(sizeof(*q));
if (NULL == q) {
    /* malloc failed. now what ? */
    return NULL; /* maybe ? */
}
好的,对于这个例子来说,返回
NULL
在其他方面是无效的,所以返回它来表示错误是有意义的。但是

void *get_data()
{
    /* stuff */

    /* Error detected. NULL is a valid return, now what ? */

    /* stuff */
}
此外,一旦我们发出错误信号,如何发出错误信号?我已经考虑过了,但没有一个令人满意的解决方案

  • 使用
    errno
    或其他全局对象是不正确的 我想做的事情(也许是 这些函数可以从 多线程等)

  • 我想让客户提供 某些“状态”对象可以 在电话后检查过,但是 这会使API非常难看


那么你对这个问题有什么看法?如何以干净的方式报告错误?

如果您真的想要一种多线程、可重入的报告错误的方法,我认为您不能在每次lib调用中都逃避传递指向“status”结构的指针。在其他对象状态的东西中,该结构将包含有问题的调用的结果

它确实很难看,但不一定是坏的。

将“status”参数作为指针传递似乎有点难看,但在C编程中是可以接受的,因为该语言中不存在更高级的错误报告功能

状态变量中的每一位都代表不同的错误,因此如果返回
NULL
,调用方必须测试
status&ERR\u NOMEM
status&ERR\u IO
等。错误掩码可定义如下:

#define ERR_NOMEM (1 << 0)
#define ERR_IO    (1 << 1)
...

定义错误名称(1我有几点建议

建议#1使用自定义错误号。 我知道您表示不希望使用它。我推测您担心在多线程环境中会出现错误,但我希望每个线程都应该有自己的错误存储。下面的链接表明这样做相当容易

就构建自定义错误号而言,您始终可以将错误号分为两部分…模块编号和模块错误代码

eg.
#define MODULE_NAME_error_code ((MODULE_NUMBER << 16) | (error_code))

#定义模块名称错误代码((模块编号我的第一个想法:为什么不使用stderr,用指示问题来源和原因的消息填充它?或者,可能我没有领会您的意图:)


如果没有明显的“错误返回”,则可能您的输出值不应该是返回值。该错误可能是错误号、其他一些自定义详细错误值(*cough*HRESULT)、函数成功时为true/false或其他一些有用信息(数据长度,或错误时为-1)

如果你想传递一个参数,为什么不传递一个指向结构的指针呢?这样你就可以完全改变(并决定,即使你想保持二进制兼容性)东西的工作方式和接口,比如:
mylib\u fancy\u error\u msg(&mylib\u state)
。另一个选择是让返回值具有不同的含义(或者只是返回状态)和传递对象(指针)在参数中…例如,
system
does@pmg这也是一种明智的方法。老实说,我将制作一个错误代码位掩码,并将我的位读取/写入/etc的所有错误字段放在它自己的结构中,每次运行时我都会检查它。1.因为我会污染客户端的
stderr
。2.因为
 stderr
甚至可能不可用(GUI应用程序?)3.因为客户端必须解析字符串才能找到错误(我以后将无法在不中断程序的情况下更改这些字符串)。好的。我知道你在做什么,但为了响应:)-1.如果你包含一些文本前缀,如“MyLib:”,则可以轻松过滤.2.如果您使用简单的fprintf,您将能够将输出流更改为您最喜欢的内容。此外,我认为stderr的可用性与GUI程序无关。3.无论您决定采用何种错误报告方式,这一点都是正确的。无论采用哪种方式,其他解决方案都是从函数结构返回详细的错误描述选项。因为它不要求您使用不合法的全局变量,所以我会这么做。好的,(2):也许客户端不想为了得到错误而进行I/O操作。和(3):如果我使用整数代码,客户端将不需要解析任何东西。2.是的……可能:),3.我的意思是您将无法更改特定的错误“代码”在不破坏现有依赖程序的情况下。但是…返回struct如何?必须涉及一些内存管理,但这是最灵活的解决方案IMHO?您可以通过使用线程本地存储来维护错误struct,并让函数只报告是否发生错误来实现这一点。例如,
void foo(int bar,int biz,struct my_error_t*e);
变成
int foo(int bar,int biz)
,就像普通函数一样,其中非零返回值表示错误。当错误发生时,
foo
调用
set\u my\u error
来修改线程本地错误上下文。类似地,
foo
的调用方可以调用
get\u my\u error
来检索详细的错误信息,如果它愿意的话。
int get_data(void **ptr)