「这是我参与11月更文挑战的第 2 天,活动详情查看:2021最后一次更文挑战」。
示例一
之前在这篇文章中【转载】RAII 妙用之 ScopeExit 涉及过 ## 拼接功能的使用
代码如下:
/// @note 通过一系列宏定义构造 ScopeExit 类的实例
#define _CONCAT(a, b) a##b
#define _MAKE_SCOPE_(line) ScopeExit _CONCAT(defer, line) = [&]()
#undef SCOPE_GUARD
#define SCOPE_GUARD _MAKE_SCOPE_(__LINE__)
利用宏定义中将变量名和行号拼接起来,实现了根据宏定义所在行号命名 ScopedExit 对象(防止重名)的功能
示例二
该示例的功能主要是将满足一定命名规范的函数封装为一个 Command 结构体数组
Command 结构体定义如下
/// <summary>
/// 封装了函数名和函数指针的 command 结构体
/// </summary>
struct command {
const char* name;
void (*function) (void);
};
宏定义代码如下,除了利用了之前提到的 ## 的拼接功能外(假设封装的每个函数名后缀都为 _command),还有 # 的转字符串的功能
/// @note NAME 需要和以下实体函数的名字相符合
#define COMMAND(NAME) {#NAME, NAME##_command}
封装部分的代码为
/// <summary>
/// 封装之后,方便遍历和随机访问 commands
/// </summary>
/// <returns></returns>
struct command commands[] = {
COMMAND(quit),
COMMAND(help),
};
完整示例代码如下
/// #: 将后面的 宏参数 转为字符串,即 将后面的参数用双引号引起来
/// ##:就是用于拼接
/// @note NAME 需要和以下实体函数的名字相符合
#define COMMAND(NAME) {#NAME, NAME##_command}
/// <summary>
/// 用于初始化 command 中函数指针的实体函数
/// 名字满足上面宏定义的 NAME_command 的模式
/// </summary>
void quit_command() {
printf("I am quit command\n");
}
/// <summary>
/// 同上
/// </summary>
void help_command() {
printf("I am help command\n");
}
/// <summary>
/// 封装了函数名和函数指针的 command 结构体
/// </summary>
struct command {
const char* name;
void (*function) (void);
};
int main() {
/// <summary>
/// 封装之后,方便遍历和随机访问 commands
/// </summary>
/// <returns></returns>
struct command commands[] = {
COMMAND(quit),
COMMAND(help),
};
commands[0].function();
commands[1].function();
return 0;
}
参考文章
宏定义中 # 和 ## 的作用 该文章代码有小错误,我进行了修正