首页 > 其他分享 >C语言宏定义中的#和##(转)

C语言宏定义中的#和##(转)

时间:2023-09-10 21:34:06浏览次数:31  
标签:记号 ## C语言 int printf 实参 define 定义

https://www.jb51.net/article/282832.htm

 

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

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

1. 记号串化(#)

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

1 2 3 4 5 6 7 8 9 10 #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。

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

1 2 #define F(x, y, z)   x##y##r char F(a, b, c);

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

char abr;

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

1 2 3 4 5 6 7 8 9 10 11 12 13 #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. 分析下列程序运行结果

1 2 3 4 5 6 7 8 9 10 #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)"

上面程序运行结果如下。

标签:记号,##,C语言,int,printf,实参,define,定义
From: https://www.cnblogs.com/Cxiangyang/p/17691996.html

相关文章

  • 运行vue项目一直报错的问题的解决
    问题描述(上图为网图,自己的没来得及截图)问题解决第一个原因:vue版本过低;使用下面的语句进行版本升级:[email protected]但是我试了没啥用;第二个原因:node版本过低;使用下面的语句进行版本升级:--若是已经有更高级的版本,可以直接更换:nvmlistnvmuse版本--若是没有,就自己......
  • C++的运算符重载介绍
    所谓重载,就是赋予新的含义。函数重载(FunctionOverloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作。运算符重载(OperatorOverloading)也是一个道理,同一个运算符可以有不同的功能。实际上,我们已经在不知不觉中使用了运算符重载。例如,+号可以对不同类型(int、float等)的......
  • Codeforces Global Round 21 B. NIT Destroys the Universe
    给一个长为\(n\)的数组,可以执行以下操作任意次:选择\(l,r(1\leql<r\leqn)\),让\(\foralli(l\leqi\leqr),a_i=mex(\{a_l,a_{l+1},\cdots,a_{r}\})\)。问最小操作数使得\(\foralli,a_i=0\)。观察:答案\(\leq2\),因为对\([1,n]\)操作不超过两次......
  • 振弦传感器在岩土工程中安全监测的重要性
    振弦传感器是一种主要用于岩土工程中安全监测的专用设备,能够非常准确地测量土体的振动特性,如振动频率、振动波形、振幅等,具有高精度、高灵敏度、高响应速度等优点。在岩土工程中,振弦传感器主要用于以下方面的安全监测:1.地铁隧道施工:地铁隧道的施工过程中,需要对周围的建筑物、桥梁......
  • 延续性动词和非延续性动词
    英语动词按其动作发生的方式以及动作发生过程的长短,可分为延续性动词和非延续性动词延续性动词表示能够延续的动作,这种动作可以长时间延续下去或产生持久的影响。英语中的延续性动词比较多study,work,stand,lie,know,walk,keep,have,wait,watch,sing,read,sleep,l......
  • SQL盲注
    盲注的本质是猜解(所谓“盲”就是在看不到返回数据的情况下能通过“感觉”来判断),那能感觉到什么?答案是:差异(包括运行时间的差异和页面返回结果的差异)。也就是说想实现的是要构造一条语句来测试输入的布尔表达式,使得布尔表达式结果的真假直接影响整条语句的执行结果,从而使得系统......
  • Spring源码分析(八)容器的扩展点(BeanPostProcessor)
    在前面两篇关于容器扩展的文章,我们已经完成了对BeanFactoryPostProcessor和FactoryBean的分析,对于BeanFactoryPostProcessor而言,它能让我们对容器中扫描出来的BeanDefinition做出修改以达到扩展的目的,而对于FactoryBean而言,它提供了一种特殊创建bean的手段,能让我们将一......
  • 【230910-2】双曲线:y^2/160^2-x^2/120^2=1图线及特征
    【图像】【代码】<!DOCTYPEhtml><htmllang="utf-8"><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><head><title>双曲线:y^2/160^2-x^2/120^2=1</title><styletype=&qu......
  • 服务器重启后如何让K8S也自动重启
    在云计算和容器化时代,Kubernetes已经成为主流的容器编排解决方案,能够提供高效、自动化的服务部署和管理。然而,当服务器出现故障或需要进行维护时,我们经常需要重新启动服务器。在这种情况下,如何让Kubernetes服务也自动重启,确保其正常运行呢?以下是几个关键步骤,用于在服务器重启后自动......
  • 2-2C语言学习
    #include<stdio.h>voiddouble_value(doublen);intmain(){ doublevalue; printf("Pleaseenterthedoublevalue:"); scanf_s("%lf",&value); while(value>0.00) { double_value(value); printf("\nPleaseentert......