程序的编译过程可以分为预处理、编译、汇编三部分,其中预处理是首先执行的过程,预处理过程扫描程序源代码,对其进行初步的转换,产生新的源代码提供给编译器。
预处理过程读入源代码之后,会检查代码里包含的预处理指令,完成诸如包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码的工作。下面介绍一些C/C++中预编译的指令。
一 #指令
预处理指令以#号开头,并且#号必须是该行除了任何空白字符外的第一个字符。
#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
单纯一个#号表示空指令,没有任何作用。
二 #include指令
#include预处理指令的作用是在指令处展开被包含的文件。展开被包含的文件之后,在代码就可以正常地调用该文件中所声明的变量和函数。#include指令有两种使用方法
#include <xxx.h>
#include "xxx.h"
第一种方法将待包含的头文件使用尖括号括起来,预处理程序会在系统默认目录或者括号内的路径查找,通常用于包含系统中自带的公共头文件。
第二种方法将待包含的头文件使用双引号引起来,预处理程序会在程序源文件所在目录查找,如果未找到则去系统默认目录查找,通常用于包含程序作者编写的私有头文件。
文件包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。在大型的程序中可能会产生重复包含的问题,如
#include "a.h"
#include "b.h"
一个程序包含了a.h和b.h两个头文件,但a.h和b.h可能同时又都包含了c.h,于是该程序就包含了两次c.h,这在一些场合下会导致程序的错误,可以通过下面的条件编译进行解决。
三 #define、#undef指令
#define指令定义了一个标识符及一个串,标识符称为宏名,源程序中宏名的每次出现都会用其定义的串进行替换,称为宏替换。
#undef指令取消一个已定义的宏。
宏一般使用大写字母定义,其可以出现在程序的任意地方。宏替换仅仅是以文本串代替宏标识符的过程,该过程很容易出现一些逻辑上的错误,需要仔细处理一些关于括号的问题。
以下代码用宏定义了一个常量PI,但C++中建议使用const进行常量定义,因为宏替换并不会进行类型匹配之类的安全性检查。同时用宏定义了一个MAX函数,其好处是没有函数调用的额外开销,运行速度较快,但容易出错,而且大量的宏替换会增加代码的长度。
void test1()
{
#define PI 3.14
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
cout << PI << endl; //3.14
cout << MAX(2, 3) << endl; //3
#undef PI
//cout << PI << endl; //编译出错
}
另外还有两个特殊的运算符:
宏定义中的#运算符把跟在其后的参数转换成一个字符串称为字符串化运算符。
宏定义中的##运算符把出现在##两侧的参数合并成一个符号。
void test2()
{
#define CAT(n) "ABC"#n
cout << CAT(123) << endl;//ABC123
#define NUM(a,b) a##b
#define STR(a,b) a##b
cout << NUM(1, 2) << endl;//12
cout << STR("Hello", "World") << endl;//HelloWorld
}
————————————————
版权声明:本文为CSDN博主「sunshinewave」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sunshinewave/article/details/51020421