C++宏展开规则
这里主要记录一下宏嵌套宏的这中情况,例如下面这段代码:
#include <stdio.h>#define cat(a,b) a##b#define xcat(x,y) cat(x, y)int main()
{int ret = xcat(xcat(1, 2), 3);printf("%d\n", ret);return 0;
}
宏嵌套宏,说的直白一点就是,一个宏函数它的参数也是宏。对于这种情况,编译器会按照下面的步骤去执行:
-
先将实参进行替换,也就是宏展开,这里的实参是一个宏。拿上面的例子来说就是,先将最外层
xcat
宏函数的两个实参xcat(1, 2)
和3
替换xcat
的形参x
和y
,得到cat(xcat(1, 2), 3)
-
检查第一步替换的实参,如果实参也是宏,检查该宏参数是否可以被展开,宏参数是否可以被展开的判断依据是,在第一步展开得到的宏体中,该宏参数的前面或者后面没有
#
和##
。拿上面的例子来说就是,第一步中的实参是xcat(1, 2)
,第一步展开的宏体就是cat(xcat(1, 2), 3)
,在这个宏体中,实参前面和后面都没有#
和##
,说明该宏实参可以继续展开。所以在第一步执行完得到cat(xcat(1, 2), 3)
后,接下来是展开xcat(1, 2)
,而不是展开最外层的cat
。所以这一步执行完得到cat(cat(1, 2), 3)
。 -
接下来是继续展开内层的
cat
而不是外层的cat
,这里有一点向函数的嵌套调用,一条道走到黑。因为第二步在将宏参数xcat(1, 2)
展开后得到的还是一个宏函数调用cat(1, 2)
,那么就会一直往下展开,直到最终无法展开为止,所以这里展开内层cat
后得到的是cat(1##2, 3)
也就是cat(12, 3)
,也就是12##3
,也就是123
。
再看下面这个例子:
#define foo a,b
#define bar(x) lose(x)
#define lose(x) (1 + (x))bar(foo);
-
展开
bar
,用实参foo
替换形参x
,得到lose(foo)
-
检测实参宏是否可以被继续展开,这里是可以的,于是展开
foo
,得到lose(a, b)
-
到这里,
a
和b
都不是宏,无法再继续往下展开,所以就返回去展开lose
,但是lose
宏只接收一个参数,而当前有两个参数,所以这里编译的时候会报错。这里正确的改发有下面两种:
#define foo (a,b)
或者
#define bar(x) lose((x))