代码生成

通过编写重复代码,X-Macros 可用于代码生成:迭代列表以执行某些任务,或声明一组常量,对象或函数。

这里我们使用 X-macros 声明一个包含 4 个命令的枚举和一个名称为字符串的映射

然后我们可以打印枚举的字符串值。

/* All our commands */
#define COMMANDS(OP) OP(Open) OP(Close) OP(Save) OP(Quit)

/* generate the enum Commands: {cmdOpen, cmdClose, cmdSave, cmdQuit, }; */
#define ENUM_NAME(name) cmd##name,
enum Commands {
  COMMANDS(ENUM_NAME)
};
#undef ENUM_NAME

/* generate the string table */
#define COMMAND_OP(name) #name,
const char* const commandNames[] = {
  COMMANDS(COMMAND_OP)
};
#undef COMMAND_OP

/* the following prints "Quit\n": */
printf("%s\n", commandNames[cmdQuit]());

类似地,我们可以生成一个跳转表来通过枚举值调用函数

这要求所有函数具有相同的签名。如果它们不带参数并返回一个 int,我们会把它放在带枚举定义的头文件中:

/* declare all functions as extern */
#define EXTERN_FUNC(name) extern int doCmd##name(void);
COMMANDS(EXTERN_FUNC)
#undef EXTERN_FUNC

/* declare the function pointer type and the jump table  */
typedef int (*CommandFunc)(void);
extern CommandFunc commandJumpTable[];

假设上面的部分包含在标题中,以下所有内容都可以在不同的编译单元中:

/* generate the jump table */
#define FUNC_NAME(name) doCmd##name,
CommandFunc commandJumpTable[] = {
  COMMANDS(FUNC_NAME)
};
#undef FUNC_NAME

/* call the save command like this: */
int result = commandJumpTable[cmdSave]();

/* somewhere else, we need the implementations of the commands */
int doCmdOpen(void) {/* code performing open command */}
int doCmdClose(void) {/* code performing close command */}
int doCmdSave(void) {/* code performing save command */}
int doCmdQuit(void) {/* code performing quit command */}

在实际代码中使用的该技术的示例是用于 Chromium 中的 GPU 命令调度