1
C/C ++程序设计
1.2.10.1 10.1 宏定义

10.1 宏定义

宏定义预编译指令是以“#”开头,使用“define”作为宏定义的指令。宏定义的作用是使用一个标识符来代表一个字符串,这种特殊的指令称之为宏定义,“标识符”为所定义的宏名,“字符串”可以是常数、表达式、格式串等。规模比较大的项目都会用大量的宏定义来组织代码。根据标识符形式的不同,宏定义可以分成两种类型,分别是变量式宏定义和函数式宏定义。

10.1.1 变量式宏定义

变量式宏定义的书写类似于变量的声明,用来定义常量。

定义的一般形式为:

#define标识符字符串

例如:

#define PI 3.1415926

宏定义的作用是使用标识符PI来代表程序中"3.1415926"这个字符串,标识符PI称为“宏名”,#define称为宏定义指令,在预编译时将宏名替换成字符串的过程称为“宏展开”。在宏展开后,程序中出现的所有的标识符PI都将用"3.1415926"来代替。

宏定义不仅使用方法简单,而且还可以实现一概全改。

【例10.1】使用变量式宏定义计算圆的周长和面积。

代码如下:

img352

img353

运行结果如图10-1所示。

img354

图10-1

分析:

题目中圆周率PI即为变量式宏定义,代码第2行以后出现的宏名PI都将被替换成字符串"3.1415926"。变量式宏定义的使用让程序显得简洁了不少,而且如果需要修改圆周率PI的数值也方便很多,只需要修改第2行的宏定义,不必全文修改。

和变量定义一样,宏也是可以嵌套定义的。

例如:

#define A(1+2)

#define B((A)*(A))

#define C((B)+(B))

先定义了A,然后定义B,最后又定义了C,次序不能颠倒。宏展开后如下:

#define A(1+2)

#define B((1+2)*(1+2))

#define C(((1+2)*(1+2))+((1+2)*(1+2)))

经过宏展开,宏A代表字符串3,宏B代表字符串9,宏C代表字符串18,宏定义中括号的使用是非常重要的,修改宏A和宏B的定义如下所示:

#define A 1+2

#define B A*A

宏展开后:

#define B 1+2*1+2

此处经过宏展开,宏B代表字符串5,而不是期望的9,这样就展示出括号在宏定义中的重要性了。

关于变量式宏定义,还有以下几点需要注意:

(1)一般用大写字母表示宏名,这是习惯问题,不属于严格规定,目的是为了和变量名区别。

(2)宏定义不是C语句,它的使用仅是辅助C程序,提高程序效率,所以宏定义的结尾不写分号。如果加了分号,那么分号就会被认为是用来替换的字符串的一部分,分号也将被一起替换。

例如:

#define NEWLINE"\n";

程序中执行替换printf(NEWLINE);时就会生成下面的代码:

printf("\n";);

预编译的宏定义是用宏名代替一个字符串,只作简单置换,不作正确性检查。只有在编译已被宏展开后的源程序时才会发现语法错误并报错。

(3)宏展开时将不会替换程序中所含字符串中和宏名相同的字符。

例如:

#define TEN 10

程序中有如下代码:

printf("TEN=%d\n",TEN);

宏展开后的结果是:

printf("TEN=%d\n",10);

(4)宏定义不同于变量的定义,它只起到替换的作用,不会分配内存空间。

(5)宏定义通常是单行的,也可以是多行形式,定义方法就是使用反斜杠“\”,反斜杠后要紧跟回车键。

img355

10.1.2 函数式宏定义

函数式宏定义的书写类似于函数,用来定义稍复杂些的带参数的表达式。

其定义的一般形式为:

#define标识符(参数列表)字符串

例如:

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

字符串中包含标识符中的参数,参数列表可由一个或者多个参数组成。标识符MAX有两个参数a和b,程序中MAX(a,b)形式的标识符将被替换成相应的问号表达式。

【例10.2】使用函数式宏定义求两个数中最大值并计算两个数的乘积。

代码如下:

img356

img357

运行结果如图10-2所示。

img358

图10-2

分析:

程序中定义了一个取两个数最大值的宏MAX,又定义了一个取两个数乘积的宏MUL,都是由两个参数组成的。

宏MAX(x,y)(x>y?x:y),展开后为a+b>c+d?a+b:c+d,根据运算符的优先级和结合性,结果跟预期是一致的,求a+b和c+d的中的最大值。

宏MUL(x,y)(x*y),展开后为a+b*c+d,根据运算符的优先级和结合性,宏MUL的运行结果不是预期的21,而是奇怪的11,更正方法在前文已经提到,就是给参数添加括号。

修改上例宏MUL(x,y)如下:

img359

当调用宏MUL(a+b,c+d)时,展开后为((a+b)*(c+d))。

10.1.3 宏定义范围

文件中的宏定义并非是从定义开始就有效直到文件结束,可以指定宏定义的作用范围,使用的方法是:

img360

【例10.3】练习使用宏定义范围。

代码如下:

img361

img362

运行结果如图10-3所示。

img363

图10-3

分析:

这道题目三次使用宏名A,每个宏定义都指定了自己的作用范围,在主函数中使用宏名A值为2,调用函数function1宏名A值为12,调用函数function2宏名A值为20。