前言
C/C++中宏定义有#最常见的用法就是用在宏定义语句的开头(如#define、#ifdef等),用来标识一个宏定义语句。除此之外,#还有两个比较重要的用法:
"#" 用来将标识符字符串化
"##" 连接两个标识符
下面就上面的两个作用,具体展开讲一讲。
“#”标识符转化为字符串
“#” 可以在宏定义中将一个标识符转化为一引号字符串。
# TO_STR(ARG) #ARG // 将参数转化为字符串,例如:
TO_STR(time) 将转化为"time"
TO_STR(a) 将转化为"a"
在一些打印中经常见到这种用法,举个例子如下:
#include <iostream>
# define LOG(ARG) cout << #ARG << " = " << ARG << endl;
using namespace std;
int main()
{
int a = 1;
int b = 2;
LOG(a+b);
return 0;
}
上面的打印结果如下:
a+b = 3
这个例子中,"#"的作用就是将a+b作为整体转化为字符串。注意,“#”将标识符转化为字符串,必须是在宏定义中,如果不是宏定义语句中,是不可以的。下面的语句是得不到上面的效果的。
#include <iostream>
using namespace std;
int main()
{
int a = 1;
int b = 2;
// #a+b 是不能将a+b转化为字符串的
cout << #a+b << " = " << a+b << endl;
return 0;
}
"##"连接两个标识符
"##"用于在宏定义中连接两个标识符。常常用于生成一系列结构化相同代码。
#define PARAMS(TYPE, ARG) TYPE TYPE##_##ARG
PARAMS(int, cellnum); // 相当于 int int_cellnum;
PARAMS(double, salary); // 相当于 double double_salary;
多重宏的展开顺序以及需要注意的地方
如果是多重宏,那么需要按照顺序逐层展开。
#define ARGS 1,2,3
#define MACROFUNC_OUTER(PARAMS) MACROFUNC_INNER(PARAMS)
#define MACROFUNC_INNER(A,B,C) A + B + C
int a = MACROFUNC_OUTER(ARGS);
// 上面的宏MACROFUNC_OUTER(ARGS)最终会展开为:
1 + 2 + 3
// 具体展开过程为:
第一步:MACROFUNC_OUTER(ARGS) -> MACROFUNC_INNER(ARGS)
第二步:由于ARGS仍然为一个宏,可以继续展开,知道不能展开为止,故
MACROFUNC_INNER(ARGS) -> MACROFUNC_INNER(1, 2,3)
第三步:MACROFUNC_INNER(1,2,3) -> 1 + 2 + 3
需要特别注意的是,遇到"#"以及"##"会停止展开。
// test.cpp
#define ARG1 prefix_
#define ARG2 suffix
#define CAT(A, B) A##B
// 那么下面的式子展开结果是什么呢?prefix_suffix ?
CAT(ARG1, ARG2);
使用预处理命令进行处理:g++ -E test.cpp -o test.ii, 然后使用vim查看test.ii,结果如下:

可以看到,上面的展开并没有展开为像我们预期的那样:prefix_suffix
这是因为,在宏展开过程中遇到"#"、"##"就会停止展开。对上面的展开过程作一个分析:
CAT(ARG1, ARG2)首先展开为 ARG1##ARG2, 由于在这一步展开遇到"##",于是就不会进一步
展开ARG1以及ARG2了。
为了解决上面的问题,可以增加一个中间层:
// test.cpp
#define ARG1 prefix_
#define ARG2 suffix
#define CAT(A, B) CAT(A, B)
#define XCAT(A, B) A##B
// 那么下面的式子展开结果是什么呢?prefix_suffix ?
CAT(ARG1, ARG2);
增加一个中间层之后,CAT(ARG1, ARG2)就可以顺利展开为prefix_suffix了:
CAT(ARG1, ARG2)首先展开为 XCAT(ARG1,ARG2),展开到这一步时,由于没有遇到"#"以及"##",那么
宏参数ARG1以及ARG2会进一步展开:ARG1 -> prefix_ ARG2 -> suffix,得到:
XCAT(prefix_, suffix) —> prefix_suffix