写点什么

C 语言宏定义中的#和##

作者:向阳逐梦
  • 2023-07-16
    四川
  • 本文字数:1281 字

    阅读完需:约 4 分钟

C语言宏定义中的#和##

#和 ##是宏定义中常用的两个预处理运算符

其中 #用于记号串化,##用于记号黏结,下面分别介绍它们。

1. 记号串化(#)

记号串化可以将函数式宏定义中的实参转换为字符串。在函数式宏定义中,如果替换列表中有“#”,则其后的预处理记号必须是当前宏的形参。在预处理期间,“#”连同它后面的形参一起被实参取代。例如

#include <stdio.h>#define PSQR(x) printf("The square of " #x " is %d.\n",((x)*(x)))int main(void){    int y = 5;    PSQR(y);    PSQR(2 + 4);    PSQR( 3   *   2  );    return 0;}
复制代码

程序运行结果如下:

第 1 次调用宏时,用"y"替换 #x。第 2 次调用宏时,用"2 + 4"替换 #x。第 3 次调用宏时,用"3 * 2"替换 #x。

ANSI C 字符串的串联特性将这些字符串与 printf()语句的其他字符串组合,生成最终的字符串。例如,第 1 次调用变成:

printf("The square of " "y" " is %d.\n",((y)*(y)));

然后,字符串串联功能将这 3 个相邻的字符串组合成一个字符串:

"The square of y is %d.\n"

如果传入的实参中间有空白,则不管有多少,都被转换为一个空格,参数开头和末尾的空白都被删除。例如第 3 次调用宏时,实参“3   *   2  ”转换为“3 * 2”。

2. 记号黏结(##)

与 #运算符类似,##运算符可用于函数式宏的替换部分,它把两个记号组合成一个记号。例如,可以这样定义函数式宏:

#define XNAME(n) x ## n

然后,展开宏 XNAME(4)为 x4。

记号黏结的作用是将几个预处理记号合并为一个。在一个函数式宏定义中,如果一个预处理记号的前面或者后面有"##",则该记号将与它前面或者后面的记号合并,如果该预处理记号是宏的形参,则用实参执行合并。例如:

#define F(x, y, z)   x##y##rchar F(a, b, c);
复制代码

第 2 行的宏调用,其扩展之后如下:

char abr;

需要注意的是,在函数式宏定义中,“##”不能位于替换列表的开头和结尾。

#include <stdio.h>#define XNAME(n) x ## n#define PRINT_XN(n) printf("x" #n " = %d\n", x ## n);int main(void){     int XNAME(1) = 14; // 转换为 x1 = 14;     int XNAME(2) = 20; // 转换为 int x2 = 20;     int x3 = 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);     return 0;}
复制代码

程序运行结果如下。

3. 分析程序运行结果


#include <stdio.h>#define f(a,b) a##b#define g(a)   #a#define h(a) g(a)int main(){    printf("h(f(1,2))展开为:%s\n",h(f(1,2)));    printf("g(f(1,2))展开为:%s\n",g(f(1,2)));    return 0;}
复制代码

宏展开顺序大致可以归结为:

第一步:首先用实参代替形参,将实参代入宏文本中

第二步:如果实参也是宏,则展开实参

第三步:最后继续处理宏替换后的宏文本,如果仍包含宏,则继续展开

注意:如果在第二步,实参代入宏文本后,实参之前或之后遇到 #或 ##,实参不再展开

根据以上宏展开步骤分析第 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)"
复制代码

上面程序运行结果如下。


发布于: 刚刚阅读数: 7
用户头像

向阳逐梦

关注

人生享受编程,编程造就人生! 2022-06-01 加入

某公司芯片测试工程师,嵌入式开发工程师,InfoQ签约作者,阿里云星级博主,华为云·云享专家。座右铭:向着太阳,追逐梦想!

评论

发布
暂无评论
C语言宏定义中的#和##_向阳逐梦_InfoQ写作社区