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

 更新时间:2023年04月28日 11:15:07   作者:lhw  
这篇文章主要为大家介绍了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##r
char 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)"

上面程序运行结果如下。

以上就是C语言基本概念宏定义中的#和##教程的详细内容,更多关于C语言宏定义#和##的资料请关注脚本之家其它相关文章!

相关文章

  • 深入探究C语言中的二叉树

    深入探究C语言中的二叉树

    树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。本文将带你深入探究C语言中的二叉树,感兴趣的同学跟着小编一起学习吧
    2023-05-05
  • 详解C++中inline关键字的作用

    详解C++中inline关键字的作用

    这篇文章主要为大家介绍了C++中的inline关键字,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • 利用C语言实现扫雷游戏

    利用C语言实现扫雷游戏

    这篇文章主要为大家详细介绍了利用C语言实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 详解C++ 拷贝构造函数和赋值运算符

    详解C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符。最后,简单的分析了下深拷贝和浅拷贝的问题。有需要的朋友可以看下
    2016-12-12
  • C++超详细分析讲解内联函数

    C++超详细分析讲解内联函数

    为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数
    2022-06-06
  • C语言学生管理系统源码分享

    C语言学生管理系统源码分享

    这篇文章主要为大家分享了C语言学生管理系统的源码,帮助大家学习结构体,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 4组C语言中顺序读写文件的函数分享

    4组C语言中顺序读写文件的函数分享

    这篇文章主要为大家详细介绍了4组C语言中实现顺序读写文件的函数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • C++详细讲解图论的基础与图的储存

    C++详细讲解图论的基础与图的储存

    图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系
    2022-05-05
  • 教你用Matlab制作立体动态相册

    教你用Matlab制作立体动态相册

    没想到吧,MATLAB竟也能制作3D相册!本文将为大家详细介绍Matlab制作立体动态相册的方法步骤,感兴趣的小伙伴可以跟随小编一起动手试一试
    2022-03-03
  • 全排列算法的原理和实现代码

    全排列算法的原理和实现代码

    这篇文章主要介绍了全排列算法的原理和实现代码,全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个,需要的朋友可以参考下
    2014-08-08

最新评论