在项目开发中,错误码的设计本身就是一个重要的模块。

出错信息的处理

你会处理出错信息吗?哦,它并不是简单的输出。看下面的示例:

   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")
};