![C++从零开始学(视频教学版)(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/128/29977128/b_29977128.jpg)
6.5 预处理器
预处理器是一个独立的程序,在编译器编译程序之前运行。虽然它们不是C++的一部分,但是却扩展了C++程序设计的环境。这样做的目的是处理指令,这些指令是以#符号开始的,独立占用一行,不能使用分号结束。本节将介绍其中的一种,就是宏预处理器#define。
6.5.1 #define预处理器
#define是宏定义命令,宏定义具有这样的形式:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P121_15632.jpg?sign=1739479731-MBUpPznEiJbYD1faje1LFbOiLT3WKOCe-0-e6bc910a7bda592116a95a632245dd2f)
预处理器无论在什么时候遇到了这样的指令,任何出现identifier的地方都将被替换成replacement。标识符通常为大写字母,使用下画线代替空格。
提示
在写多行的代码define时,最好在外层加上do{}while(0),效率不会影响,并且避免在不加{}的if中使用宏的错误。
通过一个实例来说明#define如何使用。
【实例6-10】define的使用(代码6-10.txt)
新建名为“definetest”的【C++ Source File】源程序,源代码如下所示:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P121_15633.jpg?sign=1739479731-LckKOSgoXlvM4NojUtUCdHTSrZib0Elp-0-90dfd2e0fc5ac266013f5b95498e4506)
【代码详解】
在该例中,使用宏预处理器定义了YEN_PER_DOLLAR为122;在主程序中,首先定义int型变量i并赋值为5,接下来i赋值为i*宏名,将i的结果输出。
运行结果如图6-11所示。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P121_15629.jpg?sign=1739479731-ehEXvmS7Hq7BL9rqOJaCElK0JiQFLNck-0-e4ea952dd7ce410cf20e4faa8a11407b)
图6-11 代码运行结果
【实例分析】
从运行结果来看,输出i的结果就是122*5的结果。这里YEN_PER_DOLLAR看起来像一个变量,但它与变量没有任何关系,它只是一个符号或标志,在程序代码编译前,此符号会用122来代替。122不是一个数值,只是一个字符串,不会进行检查。
6.5.2 #define的作用
通过6.5.1节的介绍认识了#define预处理器,那么为什么要引入这个预处理器呢?首先,允许给一些东西命名为描述性的名字,如数字。
举个例子:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P122_15767.jpg?sign=1739479731-Sv4nGZLBf7wVaCFXHKywjD0Vog0xfkDb-0-eadb798638b5ecf5b499f2d5b3455d8d)
像122这样的数字在程序中被称为魔法数字。一个魔法数字是hard-coded数字,它在代码中没有任何意义—122表示什么呢?是转换率还是其他什么呢?它是不明确的。在一些复杂的程序里,通常很难判断一个hard-coded数字具体代表什么。
下面的小段代码是清晰的:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P122_15768.jpg?sign=1739479731-OoSPuycuzrMFMWBwAsJtbuq83nfQ3EME-0-2ebeeffe21f8f8036172d6e8ff76e3ce)
其次,#defined数字可以使得程序更加容易被修改。假设将转换率从122变成123,程序需要进行相应的调整。考虑下面的代码:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P122_15769.jpg?sign=1739479731-2HO5mOh9uX9ADgBrg5AMKLfRESD6xIqE-0-945c0adacafe7fa8a807a8e34017f9bc)
为了改变成新的转换率,必须将前面4个语句中的数字改变。但是第5个语句呢?这里的122是不是和其他的122具有相同意义呢?如果是,它就应该被改变;如果不是,就不需要改变,或者也许在其他地方中断。
现在考虑使用了#defined的情况,代码如下:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P122_15770.jpg?sign=1739479731-tqkTspElIBihcS2JbtZtlJYk4mf0QEEe-0-afe0d6d4961190163cb9473cde7bc007)
这时改变转换率只要改变一个数字,代码如下:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P122_15771.jpg?sign=1739479731-LFXkoGSYoGOdOOyuB9KUTXgQlIeL8lWR-0-7849235ccddd9e034d890644a5282aa6)
现在正确改变了转换率,并且不用担心将每页的行数改变。
6.5.3 const修饰符
常类型是指使用类型修饰符const说明的类型。常类型的变量或对象的值不能被更新。
提示
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。因此,定义或说明常类型时必须进行初始化。
1.一般常量
一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后,例如:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P123_15870.jpg?sign=1739479731-iISzupgV60N2vHAh0dUPgIt4QyqF1o1i-0-84fd471ab044394348d1be9202af3e02)
或
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P123_15871.jpg?sign=1739479731-qA8KZtkhAWHJ1kLj2lEY0icTQxBazOys-0-7f966e9dc76b290cbf3546bcb9841964)
定义或说明一个常数组可采用如下格式:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P123_15872.jpg?sign=1739479731-bBc7fcD3J8KIc3rXTIGBDgJuNnXFs9Co-0-f3637afa27a3dee3212a0b59c9770aed)
2.常对象
常对象是指对象常量,定义格式如下:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P123_15873.jpg?sign=1739479731-ob92Loov4b0JIX7e63wEJjjfP9JvcyiT-0-8583a45b0d0bee27348b079593c0dd7d)
或
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P123_15874.jpg?sign=1739479731-j9HGh8hklN5hho4JuHN1Q1jAyEP17R16-0-62c4ac9fec180f6b4dc23367bb315ddc)
定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。