前言
C++预处理指令(Preprocess)是指在C++程序源代码被编译之前,由预处理器C++程序源代码进行的处理。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的符号用来支持宏调用。
预处理的由来
在C++的历史发展中,有很多的语言特征(特别是语言的晦涩之处)来自于C语言,预处理就是其中的一个把C++从C语言那里把C语言预处理器继承过来。
预处理指令特点
C++预处理不会对程序进行词法解析,其以直接的替换为主,方便编译器的后续操作。
常用的预处理指令
注意:所有指令在一般情况下以换行(Newline)为分隔,即一条指令只包括一行。
条件编译
指令 | 作用 | 备注 |
#if | 如果 | |
#else | 否则 | |
#elif | 否则如果 | |
#endif | 结束条件 | |
#ifdef | 如果定义了一个符号, 就执行操作 | 或 #if defined |
如果表达式成立,则处理后包含此段代码。
宏定义及运用
指令 | 作用 |
#define | 定义宏 |
#undef | 取消宏定义 |
C++宏定义将一个标识符定义为一个字符串,源程序中的该标识符均以指定的字符串来代替。前面已经说过,预处理命令不同于一般C++语句。因此预处理命令后通常不加分号。这并不是说所有的预处理命令后都不能有分号出现。由于宏定义只是用宏名对一个字符串进行简单的替换,因此如果在宏定义命令后加了分号,将会连同分号一起进行置换。
宏定义
#define PI 3.1415926
#define yuan_S(r) PI*r*r
如上,这里定义了两个宏,可以看出,一般的宏都遵循#define 宏名 宏体的规律,带参数的一般形式遵循#define 宏名(参数表) 宏体的规律,<宏名>与左括号之间不能出现空格,否则空格右边的部分都作为宏体。
宏的注意
printf("半径为1+1的圆的面积约为%f",yuan_S(1+1));
但执行这段代码时,输出结果为5.1415926,因为程序会把yuan_S(1+1)识别为PI*1+1*1+1,结果为5.1415926。为了避免这种情况,应把yuan_S定义为
#define yuan_S(r) (PI)*(r)*(r)
编译器自带的宏
这些宏不需要自己定义,编译器自带。
__LINE__ 当前源文件中的代码行号,十进制整数
__FILE__源文件的名称,字符串字面量
__DATE__ 源文件的处理日期,字符串字面量,格式: 月份 日期 年份 。其中月份为 Jan Feb 等英文缩写;日期为当天的日期 ; 年份是四位的年份。如
printf("%s",__DATE__);
输出
Apr 8 2024 //这天是2024年4月8日
__TIME__ 源文件的编译时间,也是字符串字面量。格式是 hh:mm:ss 。
__STDC__ 这取决于实现方式,如果编译器选项设置为编译标准的C代码,通常就定义它,否则就不定义它。
重新定义当前行号和文件名
#line 指令指示预处理器将编译器的行号和文件名报告值设置为给定行号和文件名。
错误信息
#error 指令指示预处理器将输出编译错误消息,停止编译,如
#error 此C++程序错误!
此代码就会使程序输出“此C++程序错误!”并停止编译。
#warning 指令也输出编译错误消息,但不会停止编译
引用头文件
这个我们再熟悉不过了,平时编写程序都会用到,如果你蒙了,请看代码(VCR)
#include<bits/stdc++.h> //引用万能头文件
using namespace std; //标准命名空间
int main(){ //主函数
cout<<"Hello,Word!"; //输出语句
}
想起来了吧,#include 指令可以引用一个头文件,没有引用头文件就无法使用头文件包含的语句。一般常用的用法有两种:
#include <header>
#include "myheader.h"
前者尖括号用来引用标准库头文件,后者双引号常用来引用自定义的头文件。
布局控制
#pragma 专门用于实现预先定义好的选项,其结果在编译器说明文档中进行了详细的解释。编译器未识别出来的#pragma指令都会被忽略。