C语言笔记7--预处理器(preprocessing)

来源:互联网 发布:网络平台信息维护合同 编辑:程序博客网 时间:2024/05/12 17:21

C语言笔记7--预处理器(preprocessing)

总论:
编译一个C程序涉及很多步骤,其中第一步称为预处理(preprocessing)阶段,C预处理器(preprocessor)在源代码编译之前对其进行文本性质的操作。

它的主要任务包括删除注释、插入被#include指令包含的内容、定义和替换由#define指令定义的符号以及确定代码的部分内容是否应该根据一些条件编译指令进行编译。


文件包含
函数库文件包含两种不同类型的#include文件包含:函数库文件和本地文件。
1、函数库头文件,函数库头文件使用的语法:

#include <filename>
对于fiename,并不存在任何限制,标准库文件以一个.h后缀结尾。编译器在标准位置处查找函数头文件。

2、本地文件包含,语法格式:
#include  "filename"
编译器自行决定是否把本地形式的#include和函数库形式的#include区别对待。
可以对本地头文件先使用一种特殊的处理方式,如果失败,编译器再按照函数库头文件的处理方式对它们进行处理。

说明:

处理本地头文件的一种常见策略就是在源文件所在的当前目录进行查找,如果该头文件并未找到,编译器就像查找函数库头文件一样在标准位置查找本地头文件。
可以在所有的#include语句中使用双括号而不是尖括号。

3、对函数库头文件使用尖括号的另一个较好的理由是可以给人们提示为函数头文件而不是本地文件。


预定义(宏定义)

1、#define定义常量

#define  IP 3.14
有了这条指令以后,每当有符号IP出现在这条指令后面时,预处理器就会把它替换成3.14。
替换文本并不仅限于数值字面值常量,使用#define指令,可以把文本替换到程序中。

2、#define替换

(1)、当使用邻近字符串自动连接的特性,把一个字符串分成几段,每段实际上都是一个宏参数。如:

#define PRINT(FORMAT, VALUE) \    printf("the value is " FORMAT "\n",VALUE)int main(){    int x = 12;    PRINT("%d", x + 3);     return 0;}
输出:the value is 15

说明:此技巧只有字符串常量作为宏参数给出时才能使用。

(2)、当使用预处理器把一个宏参数转换为一个字符串,#argument这种结构被预处理器翻译为”argument”。如:

#define PRINT(FORMAT,VALUE) \    printf("the value of #VALUE is " FORMAT "\n", VALUE )int main(){    int x= 12;    PRINT("%d", x+3);}
输出:the value of x+3 is 15 

3、宏与函数

宏非常频繁地用于执行简单的计算,比如在两个表达式中寻找其中较大或较小的一个:

#define MAX(a,b) ( (a) > (b) ? (a) : (b) 


嵌套文件包含

嵌套#include文件的一个不利之处在于它使得很难判断源文件之间的真正依赖关系。另一个不利之处在于一个头文件可能会被多次包含。

解决这个问题,可以使用条件编译:

#ifndef   _HEADERNAME_H#define    _HEADERNAME_H/***All the stuff thatyou want in the header file */#endif 

条件编译

1、在编译一个程序时,如果可以选择某条语句或某组语句进行翻译或者被忽略,常常显得很方便。用于调试程序的语句就是一个明显的例子。它们不应该出现在程序的产品版本中,但是,如果以后做一些维护性修改时,又可能需要重新调试该语句。因此就需要条件编译。

2、条件编译(conditional compilation)用于实现该目的。使用条件编译,可以选择代码的一部分是被正常编译还是完全忽略。

3、用于支持条件编译的基本结构是#if指令和其匹配的#endif指令。

#if  constant-expression    statements#endif
其中constant-expression(常量表达式)由预处理器进行求值。如果它的值是非0值(真),那么statements部分被正常编译,否则预处理器就安静地删除它们。所谓常量表达式,就是说它或者是字面值常量,或者是一个由#define定义的符号。如果变量在执行期间无法获得它们的值,那么它们如果出现在常量表达式中就是一非法的。因为它们的数值在编译时是不可预测的。

将所有的调试代码都以下面的形式出现:
#if DEBUG    printf("x=%d ,y=%d\n",x,y);#endif
如果我们想编译这个代码,可以用下面的代码实现
#define  DEBUG 1
如果想忽略,则只要把这个符号定义为0就可以了。

条件编译的另一个用途是在编译时选择不同的代码部分。为了支持该功能,#if指令还具有可选的#elif和#else字句。
语法功能是:
#if constant-expression    statements#elif constant-expriession    other   statements#else      other   statements#endif 
#elif字句出现的次数可以不限。每个constant-expression(常量表达式)只有当前面所有常量表达式的值都为假时才会被编译。

#else子句中的语句只有当前面所有的常量表达式值都为假时才会被编译,在其他情况下它都会被编译。

4、是否被定义
测试一个符号是否已经被定义是可能的。在条件编译中完成这个任务往往更为方便,因为程序如果并不需要控制编译的符号所控制的特性,它就不需要被定义。如:

#ifdef  symbol  


常用预定符号

__FILE__    //用%s进行输出,输出结果为源程序名。__LINE__    //用%d进行输出,输出结果为文件当前行号。__DATE__    //用%s进行输出,输出结果为文件被编译的日期__STDC__    //用%d进行输出,如果编译器遵循ANSIC,其数值为1。否则未定义。


0 0