预处理

 一、什么是预处理

  通常执行流程为:编辑源文件产生.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()。