预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。
  在C语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。要完成这些工作,需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。
  预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:
  指令             用途
  #           空指令,无任何效果
  #include    包含一个源代码文件
  #define     定义宏
  #undef      取消已定义的宏
  #if         如果给定条件为真,则编译下面代码
  #ifdef      如果宏已经定义,则编译下面代码
  #ifndef     如果宏没有定义,则编译下面代码
  #elif       如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
  #endif      结束一个#if……#else条件编译块
  #error      停止编译并显示错误信息
  一、文件包含
  #include预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也是说一个被包含的文件中还可以包含其他文件。标准C编译器至少支持八重嵌套包含。
  预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。这样可以在多次包含同一个头文件时,通过给定编译时的条件来达到不同的效果。例如:
  #define AAA
  #include "t.c"
  #undef AAA
  #include "t.c"
  为了避免那些只能包含一次的头文件被多次包含,可以在头文件中用编译时条件来进行控制。例如:
  /*my.h*/
  #ifndef MY_H
  #define MY_H
  ……
  #endif
  在程序中包含头文件有两种格式:
  #include <my.h>
  #include "my.h"
  第一种方法是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种方法是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。
  采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。一个应用程序既包含编译器提供的公共头文件,也包含自定义的私有头文件。采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。