在今天工作中使用相对简单的C代码时,我开始做了一点日梦,并编写了以下库来有效地生成错误消息。陪审团仍然是 - 在我看来,至少 - 这是否是一种更有效的方法,而不仅仅是perror
与errno
适应你的目的......它甚至不需要是一个“库“根本就是一组宏。
现在,我正在调用库elib
:
#ifndef _ELIB_H_
#define _ELIB_H_
struct ErrorMap {
void (*fp);
int errorCode;
char * message;
};
#define eperror(...) fprintf(stderr, ##__VA_ARGS__)
char * getErrorMsg(struct ErrorMap *, void (*fp), int);
#endif /* _ELIB_H_ */
#include <stdlib.h>
#include "elib.h"
char * getErrorMsg(struct ErrorMap * errorMap, void (*fp), int code)
{
int i;
// TODO: Replace naive search
for (i=0; errorMap[i].fp != NULL; i++)
{
if (errorMap[i].fp == fp && errorMap[i].errorCode == code)
{
return errorMap[i].message;
}
}
return NULL;
}
#include <stdio.h>
#include <string.h>
#include "elib.h"
int xyzlib_openFile(int);
int xyzlib_putStuff(char *);
static struct ErrorMap xyzlib_ErrorMap [] = {
{xyzlib_openFile, -1, "Argument is less than 3"},
{xyzlib_putStuff, -1, "Argument is NULL"},
{xyzlib_putStuff, -2, "Length of argument is 0"},
{xyzlib_putStuff, -3, "Stuff is too long"},
{NULL, 0, NULL}
};
int xyzlib_openFile(int fd)
{
if (fd > 3)
{
return (-1);
}
// open a file.. or something.
return 0;
}
int xyzlib_putStuff(char * stuff)
{
if (stuff == NULL)
{
return (-1);
}
if (strlen(stuff) == 0)
{
return (-2);
}
if (strlen(stuff) > 3)
{
return (-3);
}
// do something ...
return (0);
}
int main(int argc, char ** argv)
{
int code;
if (argc != 2)
{
printf("Usage: %s <arg>\n", argv[0]);
return 1;
}
code = xyzlib_putStuff(argv[1]);
if (code < 0)
{
eperror("Error: %s\n", getErrorMsg(xyzlib_ErrorMap, xyzlib_openFile, code));
}
}
基本上,您在ErrorMap表中定义/注册返回码,如果您收到错误指示(响应值&lt; 0),那么getErrorMsg
将通过注册表查找相应的代码和功能,以获得正确的信息。我认为值对于给定库采用这种方法进行错误报告,可以按功能(而不是全局)定义错误代码 - 简化所有代码的管理。
然而,除了查找相应消息的小开销之外,采用这种方法的所有C代码都需要每个函数(不返回非负整数)返回int
,然后使用第一个参数是指向返回值的指针 - 稍微非惯用但常用。
让我们说目标市场是高可靠性嵌入式设备的软件(但资源不受限制)。
有什么想法?提前谢谢。
答案 0 :(得分:1)
我真的没有看到这一点,对不起。也许这是因为我如何处理C中的错误代码。基本上我将错误值定义为单个模块的接口的一部分。模块之间的错误值确实发生冲突,即我不关心两个模块的不同错误代码是否具有相同的数值。为了对不同的枚举进行强类型检查,我通常将它们包装成结构。但我从不真正关心为每个函数创建唯一的错误代码,这正是您的方法所针对的。
同样,这是我的具体,但我从未真正感到有必要这样做。为整个模块定义的错误代码通常适合在实现此模块的过程之间传递。那么如果你的方法实际上可以映射到模块边界而不是函数呢? :)