在项目中有时会遇到这样的情况:枚举信息需要关联相关的信息。
比如,定义一系列的故障类型 , 为了便于故障进行日志输出 , 一般会定义一个与之关联的字符串数组。
typedef enum
{
PARAM_ERR,
PARSER_ERR,
TIMEOUT_ERR,
NOTEXIT_ERR,
...
}SYS_ERR_t;
const char* ERR_INFO[]=
{
"param error",
"parser error",
"timeout error",
"not exit error"
};
#define ERR_STR(x) ERR_INFO[x]
void test(void)
{
printf(ERR_STR(PARAM_ERR));
printf(ERR_STR(NOTEXIT_ERR));
}
目前这种定义方法 ,枚举和字符串需要同时修改 ,有可能造成只增加枚举而导致数组越界
使用X宏
#define ERR_T \
X(PARAM_ERR , "param error")\
X(PARSER_ERR , "parser error")\
X(TIMEOUT_ERR , "timeout error")\
X(NOTEXIT_ERR , "not exit error")
#define X(a , b) a,
typedef enum
{
ERR_T
}SYS_ERR_t;
#undef X
#define X(a , b) b,
const char* ERR_INFO[]=
{
ERR_T
};
使用X宏最终只需要 修改 ERR_T 即可 ,减少出错的可能性 ,至于为啥叫X 宏 , 没有找到相关说明,本质是使用了#undef 对 X进行了取消定义,进行重定义 , 导致 枚举 和数组 使用相同的 ERR_T 但 表示的内容不同 ,这里很好的说明了预处理阶段 只是 一个替换过程 ,程序 预处理完成后 ,所有的宏都不将存在,而是替换成了对应的文本。
另一个实用的例子 :
定义一种数据帧格式 , 功能码 加有效字段 ,不同功能码长度不同 ,附带不同信息
typedef struct
{
uint8_t cmd;
uint8_t len;
const char* info
}p_cmd_t;
enum
{
LAP_CMDUL_CFRM = 0x00,
LAP_CMDUL_PPAT = 0x02,
LAP_CMDUL_TEMP = 0x10,
LAP_CMDUL_ALERT = 0x0F,
LAP_CMDUL_TOTAL_FLOW = 0x71,
LAP_CMDUL_RATE_FLOW = 0x72,
LAP_CMDUL_REVERSE_FLOW = 0x73,
LAP_CMDUL_FROZEN_FLOW = 0x74,
LAP_CMDUL_VER = 0x90,
LAP_CMDUL_TIMEUL = 0x98,
};
p_cmd_t cmd_tab[]=
{
{LAP_CMDUL_CFRM , 1 , "LAP_CMDUL_CFRM" },
{LAP_CMDUL_PPAT , 2 , "LAP_CMDUL_PPAT" },
{LAP_CMDUL_TEMP , 3 , "LAP_CMDUL_TEMP" },
{LAP_CMDUL_ALERT , 4 , "LAP_CMDUL_ALERT" },
{LAP_CMDUL_TOTAL_FLOW , 5 , "LAP_CMDUL_TOTAL_FLOW" },
{LAP_CMDUL_RATE_FLOW , 6 , "LAP_CMDUL_RATE_FLOW" },
{LAP_CMDUL_REVERSE_FLOW , 7 , "LAP_CMDUL_REVERSE_FLOW"},
{LAP_CMDUL_FROZEN_FLOW , 8 , "LAP_CMDUL_FROZEN_FLOW" },
{LAP_CMDUL_VER , 9 , "LAP_CMDUL_VER" },
{LAP_CMDUL_TIMEUL , 9 , "LAP_CMDUL_TIMEUL" },
};
X宏的实现方法
#define CMD_LIST \
X(LAP_CMDUL_CFRM , 0x00 , 1 , "LAP_CMDUL_CFRM")\
X(LAP_CMDUL_PPAT , 0x02 , 2 , "LAP_CMDUL_PPAT")\
X(LAP_CMDUL_TEMP , 0x10 , 3 , "LAP_CMDUL_TEMP")\
X(LAP_CMDUL_ALERT , 0x0F , 4 , "LAP_CMDUL_ALERT")\
X(LAP_CMDUL_TOTAL_FLOW , 0x71 , 5 , "LAP_CMDUL_TOTAL_FLOW")\
X(LAP_CMDUL_REVERSE_FLOW, 0x72 , 6 , "LAP_CMDUL_REVERSE_FLOW")\
X(LAP_CMDUL_FROZEN_FLOW , 0x73 , 7 , "LAP_CMDUL_FROZEN_FLOW")\
X(LAP_CMDUL_VER , 0x90 , 8 , "LAP_CMDUL_VER")\
X(LAP_CMDUL_TIMEUL , 0x98 , 9 , "LAP_CMDUL_TIMEUL")\
/*以下内容无需再修改*/
#define X(a ,b , c ,d) a = b,
enum
{
CMD_LIST
};
#undef X
#define X(a , b ,c ,d) {b,c,d},
p_cmd_t cmd_tab[]=
{
CMD_LIST
};
#undef X
总体来看 ,只是将分散的修改集中到了一起 ,修改的时候方便,不会出错。而且可以将CMD_LIST 任意成员进行关联 ,只需要重定义X 即可。可能两个事务的关联还难以体现X宏的 作用 , 当多个定义都有关联时 , 修改一个需要同步修改其他的 , 这个时候才能体现X宏的作用。