编译一个C程序的第1个步骤是预处理(preprocessing)阶段。C预处理器在源代码编译之前对其进行一些文本性质的操作。它的主要任务包括删除注释、插入被#include指令包含的文件的内容、定义和替换由#define指令定义的符合以及确定代码的部分内容是否应该根据一些条件编译指令进行编译。
1. #define
用法:
#define name stuff
有了这条指令以后,每当有符合name出现在这条指令后面时,与处理器就会把它替换成stuff
所有用于对数值表达式进行求值的宏定义都应该整个表达式两边加上一对括号。
使用#undef移除一个宏定义。
2.条件编译
#if constant-expression
statements
#endif
其中,constant-expression(常量表达式)由预处理器进行求值,如果它的值非零值(真), 那么statements部分就被正常编译,否则预处理器就安静第删除它们。
例如,将你所有的调试代码都以下面这种形式出现:
#if DEBUG printf("x=%d, y=%d\n",x,y); #endif
这样,不管我们是想编译还是忽略这个代码都很容易办到。如果想要编译它,只要使得
#define DEBUG 1
这个符号定义就可以了。如果想要忽略它,只要把这个符号定义为0就可以了。
条件编译的另一个用途是在编译时选择不同的代码部分。为了支持这个功能,#if指令还具有可选的#elif和#else子句。
是否被定义?
测试一个符号是否已被定义:
#ifdef symbol
#ifndef symbol
3.文件包含
#include指令使另一个文件的内容被编译。替换方式:预处理器删除这条指令,并用包含文件的内容取而代之。这样,一个头文件如果被包含到10个源文件中,它实际上被编译了10次。
开销问题:如果两个源文件都需要同一组声明,把这些声明复制到每个源文件中所花费的编译时间跟把这些声明放入一个头文件,然后再用#include指令把它包含于每个源文件所花费编译时间相差无几。同时,这种开销只是在程序被编译时才存在,所以对运行时效率并无影响。更重要的是,把这些声明放于一个头文件中具有重要的意义。
所以,和把一个程序需要的所有声明都放入一个巨大的头文件相比,使用几个头文件,每个头文件包含于某个特定函数或模块 。