错误码管理模块的应用

2410阅读 0评论2013-12-20 AoyamaRyo
分类:C/C++

 
错误码管理模块的应用

Author:AoyamaRyo(青山良造)
EMail:wind.river.sun@gmail.com 
      sunhaichao@chengde.lan


说明
  限于笔者水平,文中谬误之处,敬请告知笔者,不胜感激。
前言
  在C++工程中使用异常机制代替C错误码管理通常能使代码更加简洁。C++中异常产生,如果没有及时捕捉,异常值会沿函数调用堆栈层层上传,直到被捕捉(至最上层未捕捉则导致程序崩溃)。如果一个操作发生错误的概率偏高,由于上述异常的特性,该操作的异常处理会降低效率。使用异常机制还是错误码管理,视具体情况而定。
  嵌入式环境下,无论怎么侧重效率都不过分。
  本文是李云先生所著《专业嵌入式软件开发》一书相关章节的实践笔记。
       虽本笔记没有深度,但既然花了点时间,还是总结一下吧。

一、错误码结构

Error.h文件
#define MODULE_BITS 15 //模块ID所占位数,该域表示错误发生的模块
#define ERROR_BITS   16 //每个模块错误码位数,该域表示发生何种错误
#define ERROR_BIT    (1 << (MODULE_BITS + ERROR_BITS)) //符号位,1表示错误
typedef int error_t; //使用32位带符号整型数表示完整错误代号
//宏定义仅供预处理器使用(为后面所提自动生成代码的工具所用),手工编码必须使用内连函数
#define ERROR_BEGIN_OF_MODULE(_module_id)   ((_module_id) << ERROR_BITS)
inline error_t  error_begin_of_module(const short& _module_id)
        return (_module_id << ERROR_BITS);

#define ERROR_GET_MODULE_ERROR(_error_t)    ((_error_t) & ((1 << ERROR_BITS) - 1) )
inline short error_get_module_error(const int & _error_t)
  return ( _error_t & ( (1 << ERROR_BITS) - 1));

inline error_t error_gen(const short& _module_id, const short& _module_error)
    return ( error_begin_of_module(_module_id) | _module_error | ERROR_BIT );
inline error_t error_gen_abs(const short& _module_id, const short& _module_error)
    return ( error_begin_of_module(_module_id) | _module_error );
inline short error_get_module_id(const int & _error_t)
  return ((_error_t & ~ERROR_BIT ) >> ERROR_BITS);
const char *errstr(error_t _error); //由错误码获得字符串说明
///定义需要错误管理的模块ID,统一管理错误代号以及错误说明字串

二、模块ID定义

//error.h
//新添加模块,只需要填充该枚举即可,ID号自0始自动增加
#define MODULE_COUNT 30
enum module_ids{
    MODULE_ID_CFG_ETH
};

三、错误码定义

以CFG_ETH模块为例,errCfgEth.h文件:
#include "error.h"
enum errCfgEth {
///err2str enum begin
    ERR_CFG_ETH_LOST_WHICH=ERROR_BEGIN_OF_MODULE(MODULE_ID_CFG_ETH),
    ERR_CFG_ETH_LOST_ROUTE,
    ERR_CFG_ETH_LOST_PING,
    ERR_CFG_ETH_LOST_IFCONFIG,
    ERR_CFG_ETH_CHECK_ADDR,
    ERR_CFG_ETH_CHECK_MASK,
    ERR_CFG_ETH_CHECK_GATE,
    ERR_CFG_ETH_CHECK_CONFLICT,
    ERR_CFG_ETH_CHECK_INTERFACE,
    ERR_CFG_ETH_SET_ADDR_FAILED,
    ERR_CFG_ETH_SET_MASK_FAILED,
  ERR_CFG_ETH_SET_GATE_FAILED
///err2str enum end
};

  示例,如果分站自检中发现ifconfig程序文件丢失:
  return error_gen(MODULE_ID_CFG_ETH,ERR_CFG_ETH_LOST_IFCONFIG);
  至此程序中可以方便添加模块,定义无重复的错误码。错误码的添加只需改动enum module_ids、enum errCfgEth(相应模块)即可。

四、错误码转化为字符串

  仅有错误码是不够的,不便于阅读,软件版本升级后可能导致错误代号变动。故而生成日志或报告错误时需要将错误码转化为字符串释义。随着软件规模的增大,要手动编写相应的数组、函数,工作量大且容易手误出错。为此,编写一个工具根据定义模块错误码的头文件(例如errCfgEth.h、errInit.h)自动生成相关代码。
Error.h:
#include "error.h"
static struct  errstr_t{ //管理每个模块错误码对应的字符串
    int available_;
    int last_error_;
    const char **error_array_; //存放各个错误码对应的字符串
}g_errstr_array[MODULE_COUNT];
//为了通用性(用于Makefile管理的其他工程),不使用GUI
/// 这个文件由工具自动生成,主要是填充上面定义的结构体数组
#include "errstr.def"
const char *errstr(error_t _error) //转换函数
{
    static bool initialized = false;
    short          module_id = error_get_module_id(_error);
    short          error_id = error_get_module_error(_error);
    if(0 == initialized){
        errstr_init();
        initialized = true;
    }
    if(0 == _error)
        return "SUCCESS";
    if(_error > 0)
        return "ERR_ERRSTR_NOT_NEGATIVE";
    if(module_id > MODULE_COUNT)
        return "ERR_ERRSTR_INVALID_MODULE_ID";
    if(1 != g_errstr_array[module_id].available_)
        return "ERR_ERRSTR_NOT_AVAILABLE";
    if(error_id > g_errstr_array[module_id].last_error_)
        return "ERR_ERRSTR_OUT_OF_LAST";
    if(0 == g_errstr_array[module_id].error_array_[error_id])
        return "ERR_ERRSTR_NOT_DEFINED";
    return g_errstr_array[module_id].error_array_[error_id];
}

附:

生成文件errstr.def样例(本例中只演示了一个模块):
#include "errConfigEth.h"
。。。其他模块头文件

static const char *g_errstr_CFG_ETH[
ERROR_GET_MODULE_ERROR(ERR_CFG_ETH_SET_GATE_FAILED) + 1];
。。。其他模块字符串数组
void errstr_CFG_ETH_init()
{
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_LOST_WHICH)] = 
"ERR_CFG_ETH_LOST_WHICH";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_LOST_ROUTE)] = 
"ERR_CFG_ETH_LOST_ROUTE";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_LOST_PING)] = 
"ERR_CFG_ETH_LOST_PING";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_LOST_IFCONFIG)] = 
"ERR_CFG_ETH_LOST_IFCONFIG";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_CHECK_ADDR)] = 
"ERR_CFG_ETH_CHECK_ADDR";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_CHECK_MASK)] = 
"ERR_CFG_ETH_CHECK_MASK";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_CHECK_GATE)] = 
"ERR_CFG_ETH_CHECK_GATE";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_CHECK_CONFLICT)] = 
"ERR_CFG_ETH_CHECK_CONFLICT";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_CHECK_INTERFACE)] = 
"ERR_CFG_ETH_CHECK_INTERFACE";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_SET_ADDR_FAILED)] = 
"ERR_CFG_ETH_SET_ADDR_FAILED";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_SET_MASK_FAILED)] = 
"ERR_CFG_ETH_SET_MASK_FAILED";
g_errstr_CFG_ETH[error_get_module_error(ERR_CFG_ETH_SET_GATE_FAILED)] = 
"ERR_CFG_ETH_SET_GATE_FAILED";

g_errstr_array[MODULE_ID_CFG_ETH].available_ = 1;
g_errstr_array[MODULE_ID_CFG_ETH].last_error_ =
error_get_module_error(ERR_CFG_ETH_SET_GATE_FAILED);
g_errstr_array[MODULE_ID_CFG_ETH].error_array_ =
g_errstr_CFG_ETH;
}
。。。其他模块errstr_X_init()函数
static void errstr_init()
{
errstr_CFG_ETH_init();
。。。其他模块errstr_X_init()函数
}

上一篇:Windows平台利用MinGW编译DLL库
下一篇:C++浑浑噩噩的一天:Linux 定时器、多线程、Qt封装