在这个例子中,对于阅读该程序的人来说,符号MAX_NUM就有特定的含义,它代表的值给出了数组所能容纳的最大元素数目。程序中可以多次使用这个值。作为一种约定,习惯上总是全部用大写字母来定义宏,这样易于把程序红的宏标识符和一般变量标识符区别开来。如果想要改变数组的大小,只需要更改宏定义并重新编译程序即可。宏表示的值可以是一个常量表达式,其中允许包括前面已经定义的宏标识符。例如: #define ONE 1 #define TWO 2
#define THREE (ONE+TWO)
注意上面的宏定义使用了括号。尽管它们并不是必须的。但出于谨慎考虑,还是应该加上括号的。例如:
4
six=THREE*TWO;
预处理过程把上面的一行代码转换成: six=(ONE+TWO)*TWO;
如果没有那个括号,就转换成six=ONE+TWO*TWO;了。 宏还可以代表一个字符串常量,例如:
#define VERSION \"Version 1.0 Copyright(c) 2003\" 2.带参数的#define指令
带参数的宏和函数调用看起来有些相似。看一个例子: #define Cube(x) (x)*(x)*(x)
可以时任何数字表达式甚至函数调用来代替参数x。这里再次提醒大家注意括号的使用。宏展开后完全包含在一对括号中,而且参数也包含在括号中,这样就保证了宏和参数的完整性。看一个用法:
int num=8+2; volume=Cube(num); 展开后为(8+2)*(8+2)*(8+2);
如果没有那些括号就变为8+2*8+2*8+2了。
5
下面的用法是不安全的: volume=Cube(num++);
如果Cube是一个函数,上面的写法是可以理解的。但是,因为Cube是一个宏,所以会产生副作用。这里的擦书不是简单的表达式,它们将产生意想不到的结果。它们展开后是这样的:
volume=(num++)*(num++)*(num++); 很显然,结果是10*11*12,而不是10*10*10;
那么怎样安全的使用Cube宏呢?必须把可能产生副作用的操作移到宏调用的外面进行:
int num=8+2; volume=Cube(num); num++; 3.#运算符
出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。有时把这种用法的#称为字符串化运算符。例如:
#define PASTE(n) \"adhfkj\"#n main()
6
{
printf(\"%s\\n\}
宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。所以输出应该是adhfkj15。
4.##运算符
##运算符用于把参数连接到一起。预处理程序把出现在##两侧的参数合并成一个符号。看下面的例子:
#define NUM(a,b,c) a##b##c #define STR(a,b,c) a##b##c main() {
printf(\"%d\\n\printf(\"%s\\n\}
最后程序的输出为:
7
123 aabbcc
千万别担心,除非需要或者宏的用法恰好和手头的工作相关,否则很少有程序员会知道##运算符。绝大多数程序员从来没用过它。
三、条件编译指令
条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。
1.#if指令
#if指令检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,直到出现#else、#elif或#endif为止;否则就不编译。
2.#endif指令
#endif用于终止#if预处理指令。 #define DEBUG 0 main() {
#if DEBUG
8
printf(\"Debugging\\n\"); #endif
printf(\"Running\\n\"); }
由于程序定义DEBUG宏代表0,所以#if条件为假,不编译后面的代码直到#endif,所以程序直接输出Running。
如果去掉#define语句,效果是一样的。 3.#ifdef和#ifndef #define DEBUG main() {
#ifdef DEBUG printf(\"yes\\n\"); #endif
#ifndef DEBUG
9
printf(\"no\\n\"); #endif }
#if defined等价于#ifdef; #if !defined等价于#ifndef 4.#else指令
#else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。#endif指令将中指上面的条件块。
#define DEBUG main() {
#ifdef DEBUG
printf(\"Debugging\\n\"); #else
printf(\"Not debugging\\n\"); #endif
10
printf(\"Running\\n\"); }
5.#elif指令
#elif预处理指令综合了#else和#if指令的作用。 #define TWO main() {
#ifdef ONE printf(\"1\\n\"); #elif defined TWO printf(\"2\\n\"); #else printf(\"3\\n\"); #endif }
11
程序很好理解,最后输出结果是2。 6.其他一些标准指令
#error指令将使编译器显示一条错误信息,然后停止编译。
#line指令可以改变编译器用来指出警告和错误信息的文件号和行号。
#pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。
12