一般情况下,C语言
源程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译(conditional compile)。
条件编译功能
预处理程序提供了条件编译的功能。条件编译允许只编译源文件中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销,并提高程序的效率,可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。
另外,条件编译是为了让程序在各种不同的软硬件环境下都以运行。即,提高了程序的可移植性和灵活性。
例如,一个商业性的软件,所面向的用户群有着:不同的软件系统(有的是Windows XP系统,有的是Window 7系统)、不同的硬件系统(有的是Intel的处理器,有的是AMD的处理器),而这会导致同—段程序代码在不同用户的电脑上产生不同的运行效果(有的流畅、有的卡顿、有的甚至无法运行),如图1所示。
解决这类问题可以有两种方法。方法一:针对不同的环境编写不同的代码。方法二:同一段代码,针对不同的环境,预编译成不同代码,从而使得生成的程序最大程度上适应用户的软硬件环境。
条件编译格式
在C语言中,若要对程序中的代码段有条件地进行编译,就要用到条件编译命令,条件编译主要有如下几种格式:
if格式
功能:当表达式的值为真时,编译语句序列①,否则编译语句序列②。其中,#else和语句序列②可有可无。
ifdef格式
功能:当标识符已被定义时(用#define定义),编译语句序列①,否则编译语句序列②。其中#else和语句序列②可有可无。
ifndef格式
功能:该格式功能与ifdef相反。
排版
不相互嵌套
条件编译关键字语句顶格左对齐;
所含的#include语句(块) #define语句(块)甚至是被嵌套下级条件编译语句块,按照语句块嵌套的
排版方式进行
缩进排版。
函数体外
这种情况下,条件编译语句块不影响函数体
条件编译关键字语句顶格左对齐;
所含的
函数体定义无需缩进,依旧按照单个函数体定义的
排版方式进行。
函数体内
a)当条件编译语句块与被包语句所属的语句块之间没有逻辑路径交叉时
以下两种方式均可按照语句块嵌套方式进行
缩进排版 (推荐);
条件编译语句不影响原先语句块排版,条件编译语句与所包含的关键字语句块左对齐。
b)当条件编译语句块与被包语句所属的语句块之间存在逻辑路径交叉时
条件编译语句顶格左对齐,其它语句按照正常顺序排版。
应用举例
设有3个源文件如图2所示,其中存在着对同一个源文件重复包含的问题。请修改程序,不要删除代码,利用条件编译避免重复包含,使得每个源文件都能通过编译。
分析:
源文件a.c中的main()函数要调用b.c中的subl()函数,也要调用c.c中的sub2()函数,所以,文件a.c包含了b.c和c.c。源文件b.c中的sub3()函数要调用c.c中的 sub2()函数,所以b.c也包含c.c。这样一来就造成了重复包含的问题,即文件a.c包含了两次c.c,a.c的内容相当于是这样的:
其中c.c的内容出现了两遍,就有了两次sub2()函数的定义,导致编译错误。
要解决这个问题,需要用条件编译,将c.c的内容放在条件编译控制之下,即将c.c的内容修改为
这样就可以避免c.c的内容被重复包含。