前言
C++主要有三个编译阶段:预处理、转译成目的码和链接(最后的两个阶段一般才视为真正的“编译”)。
预处理器
预处理器:在编译之前运行的工具,会根据预编译指令对源代码进行“加工”,实际编译的源码是经过预处理器处理过的。
预处理器编译指令是向预处理器发出的命令,总是以符号#开头。根据程序员的指示,决定编译器实际要编译的文本内容。
比如:对于一个宏#define PI 3.1415
,在编译之前,预处理器会在代码中找到 PI 并将它替换为 3.1415 。
使用#define定义常量
- 语法: #define identifer(标识符) value(值)
栗子:
- 预处理器对宏指定的文本进行简单的替换,因此可以用宏来编写简单的函数
栗子:
为什么要使用这么多括号?
对于上面的宏AREA_CIRCLE,若在代码中这样使用
cout << AREA_CIRCLE(4+6);
使用括号时,经预处理器处理后:cout << (3.1415 * (4 + 6) * (4 + 6))
不使用括号时:cout << 3.1415 * 4 + 6 * 4 + 6
你懂。。
宏的其他作用
- 避免头文件的多次包含
假设有两个头文件class1.h,class2.h,当我们不得不让两个类相互包含时,对预处理器来说,这样会造成递归问题;
为了避免这种问题,可以使用宏和预处理器编译指令#ifndef(if-not-define)和endif。
class class1
{
......
};
class class2
{
......
};
预处理器进行死板的文本替换,这可以减轻程序员的负担,当并不是能减轻编译器的负担。
其次,对于宏PI,我们没有太大的控制权,其类型是double还是float?答案是都不是。在预处理器看来,PI就是3.1415,根本不知道其数据类型。
所以定义常量时 const 是更好的选择const double PI = 3.14215;
define与const的区别
- 起作用的阶段不同:#define在预处理阶段起作用; const在编译或者运行阶段起作用;
- 起作用的方式不同:#define进行简单的文本替换,不能进行类型检查;const定义的常量有对应的数据类型;
- 储存方式不同:#define定义的宏常量在内存中有多个备份,而const定义的常量在内存中只有一个备份;
- const常量可用于调试,而#define定义的常量不能用于调试(预处理阶段被替换掉了);