在一般情况下,源程序的所有程序行都会参加编译,以生成目标代码。但在某些特殊情况下,也许只希望对部分满足条件的程序行进行编译,这就是条件编译。
程序员可在调试程序中增加一些调试语句,以达到跟踪的目的。当程序调试好后,再利用条件编译重新编译,使调试语句不参与编译,以生成高效的代码。
常用的条件编译命令有如下三种格式:
1.格式一
#ifdef <标识符>
程序段1
#else
程序段2
#endif
其中,ifdef、else和endif都是关键字。<程序段1>和<程序段2>由若干条预处理命令或C++语句组成。该条件编译命令的功能是:如果在程序中定义了指定的<标识符>时,就用<程序段1>参与编译;否则,用<程序段2>参与编译。
如果在该格式中省略else分支,也可直接写为如下形式:
#ifdef <标识符>
程序段
#endif
2.格式二
#ifndef <标识符>
程序段1
#else
程序段2
#endif
或者
#ifndef <标识符>
程序段
#endif
其中,ifndef、else和endif都是关键字。该条件编译命令的功能是:如果在程序中末定义<标识符>时,就用<程序段1>参与编译;否则,用<程序段2>参与编译。
3.格式三
#if <常量表达式1>
程序段1
#elif <常量表达式2>
程序段2
……
……
#elif <常量表达式n>
程序段n
#else
程序段n+1
#endif
其中,if、elif、else和endif都是关键字。该条件编译命令的功能是:依次计算常量表达式的值,当为逻辑真时,则用相应的程序段参与编译;如果全部常量表达式的值都为逻辑假,则用else后的程序段参与编译。
Visual C++还提供一种类似于函数的运算符defined(),它的格式如下:
defined( <标识符> )
其功能是:当<标识符>已被定义且没有被取消时,其表达式的值为非0;当<标识符>末定义或已被取消时,其表达式的值为0。它经常被用来判断某个标识符是否已宏定义。
条件编译在程序设计中具有十分广泛的应用。例如,在程序调试时,经常需要在源程序中插入一些程序调试语句(主要是一些条件判断语句和输出语句)。这些语句是为了帮助程序调试而插入的,在调试完成后还需要逐一删除。如果用手工删除就显得比较麻烦,而且容易出错。这时,可以用条件编译命令来实现自动处理,其代码如下:
#define DEBUG 1
……
……
#if DEBUG
cout << "OK!"<<endl;
#endif
……
……
#if DEBUG
if (x<0)
cout << "Error : x < 0 "<<endl;
#endif
……
……
在该例中,#if和#endif之间的程序段是专门用于程序调试的。当程序调试完成后,应取消这些语句。这时,可将DEBUG的宏定义改为:
#define DEBUG 0
则在重新编译时,由于表达式为逻辑假,因此原#if和#endif之间的调试用程序段将不再参与编译。
在头文件“assert.h”中定义的宏assert可用来测试表达式的值。如果表达式的值为0,则assert就输出错误报告,并调用通过函数库stdlib.h中的函数abort终止程序的执行。
assert是一个十分有用的调试工具,可用于测试一个变量是否具有某个正确的值。例如,假定程序中的变量应该大于10,那么可用assert测试x的值,并在x的值不正确时输出错误报告。所用的语句为:
assert( x <=10 );
在遇到这条语句时,如果x大于10,那么就会打印出包含行号和文件名的错误报告并终止该程序的执行。这样,程序员就可以把查错的重点放在相关代码上。
如果定义了符号常量NDEBUG,其后的assert将被忽略。因此,如果不再需要assert时,可把代码行:
#define NDEBUG
插入源程序中。而无需手工删除assert。
例如,在申请动态内存时。。。。。
assert assert