C语言基本概念宏定义中的#和##教程.docx

C语言基本概念宏定义中的#和##教程.docx

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)

1亿VIP精品文档

相关文档