在C/C++预处理中,## 和 # 是两个不同的运算符,它们有不同的作用:
-
#运算符(字符串化运算符):- 将宏参数转换为字符串字面量
- 示例:
#define STR(x) #x会把参数x转换为字符串 - 使用:
STR(hello)会被替换为"hello"
-
##运算符(标记连接运算符):- 将两个标记连接成一个新的标记
- 示例:
#define CONCAT(a,b) a##b - 使用:
CONCAT(var,1)会被替换为var1
代码:
#define concat(a, b) a##b
int a = 10, b = 20;
cout << "concat(a, b) = " << concat(a, b) << endl;
这段代码会报错"未定义标识符’ab’",因为:
concat(a, b)被替换为a##b,然后变成ab- 但程序中并没有定义名为
ab的变量
要使这段代码正常工作,可以改为:
#define concat(a, b) a##b
int xy = 100; // 定义一个xy变量
cout << "concat(x, y) = " << concat(x, y) << endl; // 这会输出xy的值
或者更实用的例子:
#define VAR_NAME(n) var##n
int VAR_NAME(1) = 10; // 这会创建变量var1
int VAR_NAME(2) = 20; // 这会创建变量var2
##更详细的解释
在C++预处理器中,##是标记粘贴运算符,主要作用是将两个标识符在预处理阶段组合成新的标识符。它的核心价值体现在以下场景:
典型应用场景
- 批量生成相似代码:
#define CREATE_VAR(type, name) type var_##name
CREATE_VAR(int, count); // 展开为 int var_count
CREATE_VAR(float, total); // 展开为 float var_total
- 动态生成函数名:
#define REGISTER_HANDLER(type) void handle_##type()
REGISTER_HANDLER(error); // 生成 handle_error()
REGISTER_HANDLER(input); // 生成 handle_input()
- 平台兼容代码:
#if defined(WIN32)
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
#define MAKE_API(name) DLL_EXPORT void name##_api()
MAKE_API(network); // 根据平台生成不同修饰的函数
示例解析
#define concat(a, b) a##b
int xy = 30;
cout << concat(x, y); // 预处理阶段将x和y合并为xy
为什么不直接写xy?
- 动态生成:当需要根据参数生成不同变量名时
for(int i=1; i<4; ++i){
concat(var, i) = i*10; // 生成var1,var2,var3
}
// 等效于:
var1 = 10;
var2 = 20;
var3 = 30;
- 模板化代码:
#define CREATE_GETTER(field) \
int get_##field() { return this->##field; }
class Person {
int age;
string name;
};
CREATE_GETTER(age) // 生成 get_age()
CREATE_GETTER(name) // 生成 get_name()
关键区别
直接使用xy | 使用##宏 |
|---|---|
| 静态已知的标识符 | 动态生成的标识符 |
| 适用于固定名称 | 适用于模式化名称 |
| 人工维护每个名称 | 自动批量生成名称 |
| 代码直观易读 | 增加一定抽象性 |
当需要处理大量相似标识符时(如生成系列变量/函数),##能显著减少重复代码,提高开发效率。但在简单场景(如你的示例)中使用确实显得多余
总结:
#用于创建字符串##用于连接标识符- 使用
##时要确保连接后的标识符是已定义的
5871

被折叠的 条评论
为什么被折叠?



