1. 基本形式

#define name replacement_text

通常情况下,#define 指令占一行,替换文本是 define 指令行尾部的所有剩余部分,但也可以把一个较长的宏定义分成若干行,这时需要在待续的行末尾加上一个反斜杠符 ``。

宏定义也可以带参数,这样可以对不同的宏调用使用不同的替换文本。例:

#define max(A, B) ((A) > (B) ? (A) : (B))

2. 宏展开中的陷阱

仔细考虑一下 max 的展开式,其中的表达式会被计算两次,因此如果表达式中包含自增运算符或输入/输出等行为,则会出现不正确的情况,例如上述的宏 max

max(i++, j++)  // wrong

另外还需要注意,适当使用圆括号以保证计算次序的正确性,例如:

#define	square(x)	x * x	// wrong

当用 square(z+1) 调用该宏定义时会出错。

3. #undef

在头文件 <stdio.h> 中,getcharputchar 函数在实际中常常被定义为宏,这样可以避免处理字符时调用函数所需的运行时开销。<ctype.h> 头文件中定义的函数也常常是通过宏实现的。

可以通过 #define 取消名字的宏定义,这样做可以保证后续的调用是函数调用,而不是宏调用:

#undef getchar

int getchar(void) { ... }

4. 宏参数、###

如果在宏定义的替换文本中,参数名以 # 作为前缀则结果将被扩展为由实际参数替换该参数的带引号的字符串。例如,可以将它与字符串连接运算结合起来编写一个调试打印宏:

#define	dprint(expr)	printf(#expr " = %gn", expr)

使用语句

dprint(x/y);

调用该宏时,该宏将被扩展为:

printf("x/y" " = %gn", x/y);

其中的字符串被拼接起来了,这样,该宏调用的效果等价于

printf("x/y = %gn", x/y);

预处理器运算符 ## 为宏扩展提供了一种连接实际参数的手段。如果替换文本中的参数与 ## 相邻,则该参数将被实际参数替代,## 与前后的空白符将被删除,并对替换后的结果重新扫描。例如,下面定义的宏 paste 用于连接两个参数:

#define paste(front, back)	front ## back

因此,宏调用 paste(name, 1) 的结果将建立记号 name1


参考文献:

  1. Brian W. Kernighan, Dennis M. Ritchie.The C Programming Language (Second Edition)[M].机械工业出版社:北京,2004:76-77.

C/C++宏替换详解的更多相关文章

  1. Java中的宏变量,宏替换详解。

    群友在微信群讨论的一个话题,有点意思,特拿出来分享一下. 首先来看下面这段程序,和群友分享的大致一样. public static void main(String[] args) { String ...

  2. 【转载】C++宏定义详解

    摘自:http://blog.chinaunix.net/uid-21372424-id-119797.html   C++宏定义详解 2011-02-14 23:33:24   分类: C/C++ ...

  3. [C++] C++中的宏定义详解

    转载自:C++中的宏定义 和 C++宏定义详解 一.#define解析     #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率 ...

  4. C++宏定义详解

    一.#define的基本用法     #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质 ...

  5. [转]C++宏定义详解

    一.#define的基本用法     #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质 ...

  6. 宏定义(无参宏定义和带参宏定义),C语言宏定义详解

    1.宏定义说明 宏定义是比较常用的预处理指令,即使用"标识符"来表示"替换列表"中的内容.标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏 ...

  7. VC中预处理指令与宏定义详解

    刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...

  8. c语言宏定义详解

    1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数 ...

  9. (28)zabbix用户宏变量详解macro

    zabbix宏变量让zabbix变得更灵活,变量可以定义在主机.模板以及全局,变量名称类似:{$MACRO},宏变量都是大写的.认识了宏变量,你会感叹zabbix越发的强大. 变量可以用于如下地方: ...

随机推荐

  1. 初试Python

    01 Python简介 Python是一种跨平台的计算机程序设计语言.于1989年开发的语言,创始人范罗苏姆(Guido van Rossum),别称:龟叔(Guido). python具有非常多并且 ...

  2. logstash-配置文件详解

      kafka  将 kafka topic 中的数据读取为事件   kafka{ bootstrap_servers=> "kafka01:9092,kafka02:9092,kaf ...

  3. rpm|yum安装的查看安装路径

    [root@localhost src]# rpm -qa|grep grafanagrafana-7.1.0-1.x86_64[root@localhost src]# rpm -ql grafan ...

  4. java-类和数组

    java内存划分 Java的内存划分为5个部分: 1.栈 (Stack) : 存放的都是方法中的局部变量,方法的运行一定要在栈当中 局部变量: 方法的参数,或者是方法()内部的变量 作用域: 一旦超出 ...

  5. Linux操作系统的介绍和安装教程(Centos6.4)

    路漫漫其修远兮,吾将上下而求 Linux的简单介绍 Linux最初是由芬兰赫尔辛基大学学生Linus Torvalds开发的,由于自己不满意教学中使用的MINIX操作系统, 所以在1990年底由于个人 ...

  6. C++学习笔记---引用的本质

    本质:引用本质上是C++内部实现的一个指针常量 发现是引用的话,自动帮我们转换成指针常量 运行后,发现修改ref的值那么a的值也会一起改变,这就说明了引用的本质就是指针

  7. webmagic源码浅析

    webmagic简介 webmagic可以说是中国传播度最广的Java爬虫框架,https://github.com/code4craft/webmagic,阅读相关源码,获益良多.阅读作者博客[代码 ...

  8. 初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯

    初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯 前言 ​ 随着中美贸易战的加剧,很多公司越来越重视使用国产技术的重要性.使用国产技术,一方面可规避国外对技术的封锁造成产品核心 ...

  9. ubuntu20.04 编译安装ckermit

    ubuntu20.04编译安装ckermit 我呢之前一直使用的是ubuntu18.04,最近在安装了某个软件之后,再加上自己的操作不当最终导致ubuntu系统卡死无法进入桌面环境,早就想更新20.0 ...

  10. Java学习的第十三天

    1.object类及其方法 Java类的浅层克隆,深层克隆 2.克隆很难 3.明天学习java的继承,关键字