C语言中嵌套宏的展开规律
- 一般宏调用的展开规律是,先展开内层宏参数,再展开外层宏函数,所以展开顺序是由内而外。
-
如果宏定义中某个形参
前面
有#运算符,则调用此宏定义时,
不展开
该形参对应的实参,而是直接把这个实参变为字符串。 -
如果宏定义中某个形参
前面
有#@运算符,则调用此宏定义时,
不展开
该形参对应的实参,而是直接把这个实参变为字符。 -
如果宏定义中某个形参
前面
或者
后面
有##运算符,则调用此宏定义时,
不展开
该形参对应的实参,而是将##运算符前后的实参连接到一起形成一个新的符号,注意不是字符串。
详细实例可见下述代码。
备注:本文参考了 以下链接并作修改。链接:https://blog.csdn.net/aflyeaglenku/article/details/81504256
代码实例
#include<stdio.h>
#include<iostream>
using namespace std;
#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
#define ff(x,y) x+y
#define foo abc
#define foo2(x) x##123
#define foo123 "hehe"
#define Str1 "hello"
#define Cat2Str(x,y) x#y
void main()
{
printf("%c\n", B(1)); // B(1)------〉'1'
printf("%s\n", C(1)); // C(1)------〉"1"
printf("%s\n", h(A(1)));
//输出:T_1。
//宏展开过程为:因h(a)的宏形参前没有#或#@,形参前后没有##,因此先展开宏参数A(1)。
//h(A(1))→h(T_1)→g(T_1)→"T_1"
printf("%s\n", h(f(1, 2)));
//输出:12.
//宏展开过程为:因宏h(a)的宏形参前没有#或#@,形参前后没有##,因此先展开宏参数。
//h(f(1, 2))→h(12)→g(12)→"12"
printf("%s\n", g(f(1, 2)));
//输出:f(1,2)
//宏展开过程为:因宏g(a)宏定义的形参前有#,则不展开实参f(1,2),而是把实参作为字符串。
//g(f(1, 2))→#f(1,2)→"f(1,2)"
printf("%d\n", f(f, f(3, 4)));
//输出:7。
//宏展开顺序为:因宏定义f(a,b)的形参前后有##,因此,不展开实参, f(f, f(3, 4))→ff(3,4)→3+4
printf("%s\n", g(1)g(2)); //输出:12
//这个例子很特殊,我原以为编译器不会识别g(1)g(2),事实上,编译后会识别连在一起的宏,然后分别展开。
printf("%s\n", f(g(1), g(2))); //输出:12
//宏展开过程为:因宏定义f(a,b)的形参前后有##,所以不展开实参g(1)和g(2),f(g(1), g(2))展开后变为g(1)g(2),
//f(g(1), g(2))→g(1)##g(2)→g(1)g(2)→“12”
printf("%s\n", Cat2Str(Str1, ",nihao")); //输出:"hello,nihao"
printf("%s\n", Cat2Str(Str1, Str1)); //输出:helloStr1
//这个例子也比较经典,当宏定义某个形参前有#时,对应宏调用的实参被当作字符串
//Cat2Str(Str1, Str1)宏展开过程为:
//因为Cat2Str(x,y)的y参数前有#,直接将后面的参数转为字符串
//Cat2Str(Str1, Str1)→"hello""Str1"→"helloStr1"
printf("%s\n", foo2(foo));
//最后,上个经典例子吧。 foo2(foo)的展开可不是abc123哦。
//宏展开过程为:因为foo2(x)的宏定义形参前有##,因此,foo2(foo)对应的实参foo不再展开。
//foo2(foo)→foo##123→foo123→"hehe"
}
版权声明:本文为mary288267原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。