在项目开发中,错误码的设计本身就是一个重要的模块。
出错信息的处理
你会处理出错信息吗?哦,它并不是简单的输出。看下面的示例:
if ( p == NULL ){ printf ( "ERR: The pointer is NULL\n" ); }
告别学生时代的编程吧。这种编程很不利于维护和管理,出错信息或是提示信息,应该统一处理,而不是像上面这样,写成一个 " 硬编码"。管理错误信息,那就要有以下的处理:
/* 声明出错代码 */ #define ERR_NO_ERROR 0 /* No error */ #define ERR_OPEN_FILE 1 /* Open file error */ #define ERR_SEND_MESG 2 /* sending a message error */ #define ERR_BAD_ARGS 3 /* Bad arguments */ #define ERR_MEM_NONE 4 /* Memeroy is not enough */ #define ERR_SERV_DOWN 5 /* Service down try later */ #define ERR_UNKNOW_INFO 6 /* Unknow information */ #define ERR_SOCKET_ERR 7 /* Socket operation failed */ #define ERR_PERMISSION 8 /* Permission denied */ #define ERR_BAD_FORMAT 9 /* Bad configuration file */ #define ERR_TIME_OUT 10 /* Communication time out */ /* 声明出错信息 */ char* errmsg[] = { /* 0 */ "No error", /* 1 */ "Open file error", /* 2 */ "Failed in sending/receiving a message", /* 3 */ "Bad arguments", /* 4 */ "Memeroy is not enough", /* 5 */ "Service is down; try later", /* 6 */ "Unknow information", /* 7 */ "A socket operation has failed", /* 8 */ "Permission denied", /* 9 */ "Bad configuration file format", /* 10 */ "Communication time out", }; /* 声明错误代码全局变量 */ long errno = 0; /* 打印出错信息函数 */ void perror( char* info) { if ( info ){ printf("%s: %s\n", info, errmsg[errno] ); return; } printf("Error: %s\n", errmsg[errno] ); }
这个基本上是ANSI的错误处理实现细节了,于是当你程序中有错误时你就可以这样处理:
bool CheckPermission( char* userName ) { if ( strcpy(userName, "root") != 0 ){ errno = ERR_PERMISSION_DENIED; return (FALSE); } ... } main() { ... if (! CheckPermission( username ) ){ perror("main()"); } ... }
一个即有共性,也有个性的错误信息处理,这样做有利同种错误出一样的信息,统一用户界面,而不会因为文件打开失败, A 程序员出一个信息,B 程序员又出一个信息。而且这样做,非常容易维护。代码也易读。
当然,物极必反,也没有必要把所有的输出都放到errmsg中,抽取比较重要的出错信息或是提示信息是其关键,但即使这样,这也包括了大多数的信息。
tplink的错误处理
错误码以枚举的形式定义在tplinkType.h文件中。
typedef enum { ERR_NO_ERROR = 0, // No Error. Note: OK is defined in VxWork. ERR_BAD_PARAM, // Bad parameter, special aim at pointer is NULL ERR_NOT_SUPPORT, // not support ... ERR_THE_END, } TP_ERROR_CODE;
错误提示信息则以结构体数组形式放在了errCode.c文件中。
typedef struct { TP_ERROR_CODE switchErrorCode; UINT8 *errorString; }SWITCH_ERROR_CODE; SWITCH_ERROR_CODE ErrorCodeEnglish[] = { { ERR_NO_ERROR, "Operation successful." }, { ERR_BAD_PARAM, "Error parameters." }, { ERR_NOT_SUPPORT, "Function not supported."}, ... { ERR_THE_END, "unknown error." } };
对于结构体数组ErrorCodeEnglish中错误信息的获取,由于采取的是for循环逐个查询匹配的方式,所以无需对每一个枚举类型都给出错误信息。同时,顺序也无需一一对应。
可以利用c99新特性memberwise initialization进行改进tplink的错误处理,达到查询为常量时间、减少占用空间、顺序也无需一一对应的。示例代码如下。(根据廖泽衔的评论添加,2012-8-20)
#define DEF_ERR(_no, _str) [_no]=(_str) typedef enum { ERR_NO_ERROR=0, ERR_1TH_ERROR, ERR_2TH_ERROR, ERR_CODE_END } ERROR_CODE; char *errStr[] = { DEF_ERR(ERR_NO_ERROR, "No Error"), DEF_ERR(ERR_2TH_ERROR, "2th Error"), DEF_ERR(ERR_1TH_ERROR, "1th Error") };