X-Macro只是一种宏的使用技巧,并不是什么特殊的语法,但却在实际应用中十分高效简洁,且拓展性非常强;
首先我们介绍一下#define与#undef的用法:
#define X_MACRO(a, b) a
#undef X_MACRO
#define X_MACRO(a, b) b
#undef X_MACRO
示例:
#define X_MACRO(a, b) a
int x = X_MACRO(10, 100)
#undef X_MACRO
#define X_MACRO(a, b) b
int y = X_MACRO(10, 100)
#undef X_MACRO
#undef可以取消定义宏,然后再通过#define重新定义宏,此时得到的x,y的值分别是10和100
X-Macro其实就是通过#define与#undef实现的一种宏定义的技巧;
首先我们可以定义出这样的宏列表:
#define MACROS_TABLE \
X_MACROS(CMD_LED_ON, led_on) \
X_MACROS(CMD_LED_OFF, led_off) \
当我们需要一个命令列表时可以这样定义:
typedef enum
{
#define X_MACROS(a, b) a,
MACROS_TABLE
#undef X_MACROS
CMD_MAX
}cmd_e;
宏展开后是这样的形式:
typedef enum
{
CMD_LED_ON,
CMD_LED_OFF,
CMD_MAX
}cmd_e;
如果我们需要一个命令的字符串列表用作log打印时也可以定义这样的列表:
const char* cmd_str[] =
{
#define X_MACROS(a, b) #a,
MACROS_TABLE
#undef X_MACROS
};
宏展开后是这样的形式:
const func func_table[] =
{
“CMD_LED_ON”,
“CMD_LED_OFF”,
};
当我们需要一个函数列表时可以这样操作:
const func func_table[] =
{
#define X_MACROS(a, b) b,
MACROS_TABLE
#undef X_MACROS
};
宏展开后是这样的形式:
const func func_table[] =
{
led_on,
led_off,
};
由于函数列表与命令列表都是根据MACROS_TABLE这个宏拓展出来的,是一一对应的,所以我们可以直接使用索引的方式来调用函数:
static void cmd_handle(cmd_e cmd)
{
if(cmd < CMD_MAX)
{
func_table[cmd]((void*)cmd_str[cmd]);
}
}
使用X-MACRO对于此类的命令消息处理十分高效简洁,非常实用,且拓展性非常强。
整体代码如下:
#include <stdio.h>
#define MACROS_TABLE \
X_MACROS(CMD_LED_ON, led_on) \
X_MACROS(CMD_LED_OFF, led_off) \
/*定义命令列表*/
typedef enum
{
#define X_MACROS(a, b) a,
MACROS_TABLE
#undef X_MACROS
CMD_MAX
}cmd_e;
/*定义字符串列表用作Log打印*/
const char* cmd_str[] =
{
#define X_MACROS(a, b) #a,
MACROS_TABLE
#undef X_MACROS
};
typedef void (*func)(void* p);
static void led_on(void* p)
{
printf("%s \r\n", (char *)p);
}
static void led_off(void* p)
{
printf("%s \r\n", (char *)p);
}
/*定义函数列表*/
const func func_table[] =
{
#define X_MACROS(a, b) b,
MACROS_TABLE
#undef X_MACROS
};
/*直接通过索引的方式调用函数*/
static void cmd_handle(cmd_e cmd)
{
if(cmd < CMD_MAX)
{
func_table[cmd]((void*)cmd_str[cmd]);
}
}
void main(void)
{
cmd_handle(CMD_LED_ON);
cmd_handle(CMD_LED_OFF);
}