C语言中嵌套宏的展开规律

C语言中嵌套宏的展开规律

  1. 一般宏调用的展开规律是,先展开内层宏参数,再展开外层宏函数,所以展开顺序是由内而外。
  2. 如果宏定义中某个形参前面有#运算符,则调用此宏定义时,不展开该形参对应的实参,而是直接把这个实参变为字符串。
  3. 如果宏定义中某个形参前面有#@运算符,则调用此宏定义时,不展开该形参对应的实参,而是直接把这个实参变为字符。
  4. 如果宏定义中某个形参前面或者后面有##运算符,则调用此宏定义时,不展开该形参对应的实参,而是将##运算符前后的实参连接到一起形成一个新的符号,注意不是字符串。

详细实例可见下述代码。
备注:本文参考了 以下链接并作修改。链接:https://blog.csdn.net/aflyeaglenku/article/details/81504256

代码实例

#include
#include
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"
}

你可能感兴趣的:(C/C++基础知识,c++,c语言)