第
C语言基本概念宏定义中的#和##教程
目录#和##是宏定义中常用的两个预处理运算符1.记号串化(#)2.记号黏结(##)3.分析下列程序运行结果
#和##是宏定义中常用的两个预处理运算符
其中#用于记号串化,##用于记号黏结,下面分别介绍它们。
1.记号串化(#)
记号串化可以将函数式宏定义中的实参转换为字符串。在函数式宏定义中,如果替换列表中有#,则其后的预处理记号必须是当前宏的形参。在预处理期间,#连同它后面的形参一起被实参取代。例如
#includestdio.h
#definePSQR(x)printf(Thesquareof#xis%d.\n,((x)*(x)))
intmain(void)
inty=5;
PSQR(y);
PSQR(2+4);
PSQR(3*2);
return0;
}
程序运行结果如下:
第1次调用宏时,用y替换#x。第2次调用宏时,用2+4替换#x。第3次调用宏时,用3*2替换#x。
ANSIC字符串的串联特性将这些字符串与printf()语句的其他字符串组合,生成最终的字符串。例如,第1次调用变成:
printf(Thesquareofyis%d.\n,((y)*(y)));
然后,字符串串联功能将这3个相邻的字符串组合成一个字符串:
Thesquareofyis%d.\n
如果传入的实参中间有空白,则不管有多少,都被转换为一个空格,参数开头和末尾的空白都被删除。例如第3次调用宏时,实参3*2转换为3*2。
2.记号黏结(##)
与#运算符类似,##运算符可用于函数式宏的替换部分,它把两个记号组合成一个记号。例如,可以这样定义函数式宏:
然后,展开宏XNAME(4)为x4。
记号黏结的作用是将几个预处理记号合并为一个。在一个函数式宏定义中,如果一个预处理记号的前面或者后面有##,则该记号将与它前面或者后面的记号合并,如果该预处理记号是宏的形参,则用实参执行合并。例如:
#defineF(x,y,z)x##y##r
charF(a,b,c);
第2行的宏调用,其扩展之后如下:
charabr;
需要注意的是,在函数式宏定义中,##不能位于替换列表的开头和结尾。
#includestdio.h
#defineXNAME(n)x##n
#definePRINT_XN(n)printf(x#n=%d\n,x##n);
intmain(void)
intXNAME(1)=14;//转换为x1=14;
intXNAME(2)=20;//转换为intx2=20;
intx3=30;
PRINT_XN(1);//转换为printf(x1=%d\n,x1);
PRINT_XN(2);//转换为printf(x2=%d\n,x2);
PRINT_XN(3);//转换为printf(x3=%d\n,x3);
return0;
}
程序运行结果如下。
3.分析下列程序运行结果
#includestdio.h
#definef(a,b)a##b
#defineg(a)#a
#defineh(a)g(a)
intmain()
printf(h(f(1,2))展开为:%s\n,h(f(1,2)));
printf(g(f(1,2))展开为:%s\n,g(f(1,2)));
return0;
}
析:
宏展开顺序大致可以归结为:
第一步:首先用实参代替形参,将实参代入宏文本中
第二步:如果实参也是宏,则展开实参
第三步:最后继续处理宏替换后的宏文本,如果仍包含宏,则继续展开
注意:如果在第二步,实参代入宏文本后,实参之前或之后遇到#或##,实参不再展开
根据以上宏展开步骤分析第8行的宏调用h(f(1,2)),其展开步骤为:
h(f(1,2))--g(f(1,2))--g(1##2)--g(12)--12
第9行的宏调用g(f(1,2)),其展开步骤为:
g(f(1,2))--#f(1,2)--f(1,2)
上面程序运行结果如下。
以上就是C语言基本概念宏定义中的#和
原创力文档

文档评论(0)