![C++从零开始学(视频教学版)(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/128/29977128/b_29977128.jpg)
2.5 预处理
C++的预处理(preprocess)是指在C++程序源代码被编译之前,由预处理器(preprocessor)对C++程序源代码进行的处理。虽然预处理命令不是C++语言的一部分,但是它有扩展C++程序设计环境的作用。
提示
预处理命令是C++统一规定的,但是它不是C++语言本身的组成部分,不能直接对它们进行编译(因为编译程序不能识别它们)。
在预处理中,包含以下常用的预处理。
●#include:包含头文件。
●#if:条件。
●#else:否则。
●#elif:否则如果。
●#endif:结束条件。
●#ifdef或#ifdefined:如果定义了一个符号,就执行操作。
●#ifndef或#if!defined:如果没有定义一个符号,就不执行操作。
●#define:定义一个符号。
●#undef:删除一个符号。
●#line:重新定义当前行号和文件名。
●#error:输出编译错误,停止编译。
●#pragma:提供专用的特性,同时保证与C++的完全兼容。
下面对几个常用的预处理进行详细的说明。
1.#include在程序中包含头文件
#include的作用是将另一个源文件的内容合并到当前程序中,被合并的源文件称为“头文件”。头文件通常以.h结尾,其内容可使用#include预处理器指令包含到程序中。使用include命令可以减少程序员的重复劳动。
头文件中一般包含函数原型与全局变量。
包含头文件的形式常有下面两种。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P43_5147.jpg?sign=1739530553-qvj0LprZ06L7QIIfSZPSAJaGRaYgoSg3-0-48e2f1ac439d5bc52de68ff89449bbed)
前者<>用来引用标准库头文件,后者""常用来引用自定义的头文件。
对于前者,编译器只搜索包含标准库头文件的默认目录;对于后者,编译器首先搜索正在编译的源文件所在的目录,找不到时再搜索包含标准库头文件的默认目录。
如果把头文件放在其他目录下,为了查找到它,就必须在双引号中指定从源文件到头文件的完整路径。
2.#define定义符号、宏
(1)符号
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P43_5175.jpg?sign=1739530553-R8CrwSa9UEFqMKIo7CGOg5XmoGbh2cOj-0-7f879df615b4996e3030f8861510933a)
定义符号PI为3.14159265。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P43_5176.jpg?sign=1739530553-eSBkmF2S6Btv3BoV2PyLbTA5FWqQggCL-0-3e1c40e0063e2d4f11a028474138c17e)
取消PI的值。
这里PI看起来像一个变量,但它与变量没有任何关系,它只是一个符号或标志,在代码编译前,此符号会用一组指定的字符来代替3.14159265,不是一个数值,只是一个字符串,不会进行类型检查。
在编译前,预处理器会遍历代码,在它认为置换有意义的地方,用字符串PI的定义值(3.14159265)来代替在注释或字符串中的PI,不进行替换。
在C中常以#define来定义符号常量,如上面的“#define PI 3.14159265”,但在C++中最好使用const来定义常量。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5272.jpg?sign=1739530553-tk9d9H4bCMAmYzYb0rZZUjz8Zd8Aqb1g-0-c2a61894c99e3db26ec8270987b2d95b)
两者相比较,前者没有指定类型,容易引起不必要的麻烦,而后者定义得很清楚,所以在C++中推荐使用const来定义常量。
#define有以下缺点:
①不支持类型检查。
②不考虑作用域。
③符号名不能限制在一个命名空间中。
(2)#undef删除#define定义的符号
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5273.jpg?sign=1739530553-WC5sj24M5io2nB71dqwIqEql1HS1Vd1O-0-c028afea79d91e6c35c8e6cae02024cd)
之后不再有PI这个标识符。
(3)定义宏
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5274.jpg?sign=1739530553-RQu6hsJD1hGAniTouLzkIZvKMY6aCLN8-0-2d4684d841a465f76e16536a9cd8ea82)
将宏名中的参数代入语句中的参数。var是带入参数表。带参数的宏相当于一个函数的功能,但是比函数更加便捷。宏后面没有分号。
Print(Var)中的Print和“(”之间不能有空格,否则“(”就会被解释为置换字符串的一部分。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5275.jpg?sign=1739530553-16hP5YJ0mSM4wQs704Xv65sX2ZNtUHSO-0-0f72e5653ce7d091e1a739559abf0ccf)
调用:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5276.jpg?sign=1739530553-G2vVKzND7XfXuHQZzsUEljTMNq1ZN31a-0-4d259027ef4273e73522c1e83133d63c)
预处理器就会把它换成:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5277.jpg?sign=1739530553-BrxpZidGo3JpM6a42hPM5LkYexZce4ls-0-f4aecbe9c9b934bb67d681ec958e72fe)
所有的情况下都可以使用内联函数来代替宏,这样可以增强类型的检查:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P44_5278.jpg?sign=1739530553-fah3ULW593ziwr4NjBnL2w1ODvsVelpY-0-faf8eb822ed1bcd81b1a35c220b0547b)
调用:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P45_5295.jpg?sign=1739530553-9TrewimyFWmKcFXZrBBItuTXnktoyjk8-0-eff0cfa240371f426f821ba3bc304a9c)
使用宏时应注意易引起的错误:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P45_5302.jpg?sign=1739530553-2cMMIGDUfb2CwTdBLmTdpW0vzUzU9id1-0-f9c28af67ef4ffbe43219777c57d660b)
result=max(myval,99);替换成result=myval>99?myval:99;,这个没有问题,是正确的。调用result=max(myval++,99);替换成result=myval++>99?myval++:99;,这样如果myval>99,那么myval就会递增两次,这种情况下()是没什么用的,如result=max((x),y)替换成result=(myval++)>99?(myval++):99;。
再如:
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P45_5309.jpg?sign=1739530553-2dWLvyjv1ndxfcRzBfWftnHoLe7vr6T7-0-b15e9a8667b581c21f0a0c9b2cf16ba7)
result=product(5+1,6);替换为result=5+1*6;,所以产生了错误的结果,此时应使用()把参数括起来。
![](https://epubservercos.yuewen.com/A8BCBE/16499866604816706/epubprivate/OEBPS/Images/Figure-P45_5316.jpg?sign=1739530553-i2hIL47SozUz6URC0aMvBFuo9n5wQmDf-0-7dc4a797f567d66ba2838365ee42cfe5)
这样result=product(5+1,6);,结果正确。