错误码管理模块的应用
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()函数
}
|