在C++源程序中,允许用一个标识符来表示一个字符串,该标识符被称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”“宏替换”或“宏展开”。在本节中,使用#define命令定义的变量或函数即是典型的宏定义方式。
宏定义是由源程序中的宏定义命令完成的。宏替换是由预处理程序自动完成的。“宏”简单地可分为有参数和无参数两种。源程序被编译或被执行时,一旦遇到宏名,将视为对宏的调用。用宏体的副本替换宏名。若宏定义包含参数,则用宏名后面的参数替换宏体中的正式参数。
1.宏的范围
宏名的有效范围是从定义宏名开始,一直到该源文件结束。例如,若#define命令写在文件开头、函数之前,则该“宏”作为文件的一部分,在此文件范围内有效。
可以使用#undef命令终止宏定义的作用域。
2.无参宏定义
无参数宏的定义格式:#define标识符字符串
其中标识符就是所谓的符号常量,即“宏”名称。#define和标识符之间用空格隔开,标识符和字符串之间也用空格隔开。
当源程序被预处理(预编译)时,宏名称将被替换为字符串。掌握“宏”的概念,关键是要抓住其“换”的本质,即在对相关命令或语句的含义和功能做具体分析之前要“换”。例如,
上述语句一旦写在源代码中,程序中所有出现的“PI”将全部被替换为“3.1415926”。
一般情况下,宏名需要大写。使用宏可以提高程序的通用性和易读性,减少不一致性,减少错误输入和便于修改;宏定义语句末尾不适用分号;宏可以嵌套;宏定义不分配内存。
3.有参宏定义
使用宏时,除了一般的字符串替换,还可以进行参数替换。类似于函数调用形式,其格式为:
#define和S(A,B)之间用空格隔开,S(A,B)和“A∗B”之间也用空格隔开。参数A和B之间用逗号隔开。
需要注意的问题:
1)在进行宏定义时,如果需要使用括号,就一定要使用括号。
2)宏替换是在编译时实现的,不占用程序的执行时间。
3)函数一般只有1个返回值,宏可以有多个返回值。
例1-20
4.嵌套宏
宏还可以实现嵌套,即使用已经定义过的“宏”来定义新的宏。例如,(www.xing528.com)
此处的“嵌套”是指宏S定义时,使用了已经定义过的宏PI和R。
例1-21
5.常见的预定义宏
每一种版本的C++语言都定义了一些全局标识符。预定义宏至少需要和包含7种,另外还包括一些具有附加条件定义的宏。在C语言中,没有定义__cplusplus宏。每个预定义宏的名称以两个下画线字符开头和结尾,这些宏不能被程序员取消(#undef)或重新定义。下面依次介绍。
(1)基本预定义宏
__cplusplus 在C++编译系统对该宏进行编译时,宏定义本身被赋值为201103L。
__DATE__ 本宏提供预处理程序开始处理当前源文件的日期。在文件中,每一个__DATE__都给出同一值。日期格式表达为:mmm dd yyyy,这里mmm表示月份(如Feb,Apr);dd表示日期(如1,2,10),若小于10,则dd的第一个字符为空;yyyy表示年份(如1999,2009)。
__FILE__ 本宏提供当前正在处理源文件的文件名,表示为字符串型常量。在程序执行过程中,当处理的文件发生变化时,本宏的值均会发生变化。
__LINE__ 本宏提供当前正在处理源文件的当前行号。通常源文件的第一行定义为1,通过#line命令可改变它。
__STDC__ 本宏定义为整数1。
__STDC__HOSTED__ 若作为宿主形式使用,本宏定义为1;否则,本宏定义为0。
__STDC__VERSION__ 在C89(该版本的C语言常被称作“ANSIC”)中,本宏定义为199409L;在C99中,本宏定义为199901L,否则数值是未定义。
__TIME__ 本宏提供开始处理当前源文件的时间。它的格式为:“hh:mm:ss”。
(2)其他预定义宏
__STDC__IEC__559__ 在IEC 60559浮点数算法中,本宏定义为整数1。
__STDC__IEC__559__COMPLEX__ 在IEC 60559复数算法中,本宏定义为1。
__STDC__ISO__10646__ 在C99中,本宏定义为长整型变量,格式为:yyyymmL。其中的10646表示该宏符合ISO10646标准。
__STDC__MB__MIGHT__NEQ__WC__ 宏定义的值为整型常量1。
__STDCPP__THREADS__ 其值为整型常量1。当且仅当程序多于一个线程时,其值为1。
后续章节将会逐渐详细讲述这些宏的意义及其使用方法。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。