预处理
一、什么是预处理
通常执行流程为:编辑源文件产生.c文件----.c文件通过编译器编译为.obj文件----.obj文件通过连接器生成.exe可执行文件。在编辑之后编译之前执行的指令就是预处理。预处理分为宏定义、文件包含和条件编译等。
二、宏定义
宏定义分为变量式宏定义和函数式宏定义,宏定义习惯上标识符是大写,宏定义只起到替换作用,不会分配有内存空间。
(1)变量式宏定义
- 一般形式:#define 标识符 字符串
其中,字符串可以代替为其它以下几种都成立
#define PI 3.14159 #define LARGE < #define TRUE “\n” #define M (x*x+2*x) //不能带分号,分号会被认为是用来替换的字符串的一部分。
- 可以嵌套宏定义,如:
#define A 9.8 #define TIME 2 #define V A*TIME
- 可以为宏定义设置格式
#define A 2 …… //在这里将A替换为2才生效,……只包含函数一部分都可以
#undef A //从这里开始,A就不再是2了
(2)函数式宏定义
- 一般形式:#define 标识符([参数列表]) 字符串,如
#define C(r) 2*PI*r #define MAX(a,b) a<b?a:b printf(“%f\n”,C(radius)) printf("%d\n",MAX(2,1));
相比于真正的函数,这样做可以提高执行效率,所以当函数简短且频繁调用的时候会常用此类宏定义
三、文件包含
(1)概念:
我们之前#include<stdio.h>就是文件包含的形式,.c文件也可以被包含,只不过使用.h文件更普遍而已。实际工作中,#include指令实际上也就是把各个文件内容按照顺序合并在源文件内而已。
(2)注意点
尖括号表示在包含文件目录中找,双引号表示先在源文件目录找再去包含文件目录找,根据实际情况使用。
一个include只能由一个包含文件。如果一个源文件包含多个包含文件,每个包含文件又相互包含,c语言不允许这种情况,通过下面所讲的条件编译解决。如果没有相互包含,就为嵌套,c语言允许包含文件嵌套(如套娃)。
四、条件编译
(1)概念
条件编译是指预处理器根据条件编译指令,有条件地选择源程序代码中的一部分代码作为输出,送给编译器进行编译。主要是为了有选择性地执行相应操作,防止宏替换内容(如文件等)的重复包含。
(2)常见格式
- 和if-else结构使用方法类似
#if 条件表达式1 程序段1 #elif 条件表达式2 程序段2 #else 程序段3 #endif
- 如果没有定义标识符的判断。常用在多类头文件相互引用的情况。
#ifndef 标识符 程序段1 #else 程序段2 #endif
例如源文件aa要包含bb.h和cc.h,而bb.h中包含cc.h,这样源文件aa就包含了两次cc.h,如果在cc.h开头写上:
#ifndef CC_H { #define CC_H ...... } #endif
五、assert()宏用法
例如:
#include<stdio.h> #include<assert.h> int main() { int a=5; printf("a=%d\n",a); a=-1; assert(a>0); printf("a=%d\n",a); return 0; }
即assert()宏中的条件为假时,就会打印出错误信息,在哪个函数出错,错误在哪个文件的多少行等信息,并且程序终止运行。在开头加上#define NDEBUG的宏定义,则assert()完全在程序中失去作用,这样测试之后程序员不用删除assert()。