宏定义命令----#define
使用#define命令并不是真正的定义符号常量,而是定义一个可以替换的宏。被定义为宏的标示符称为“宏名”。在编译预处理过程时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。
在C语言中,宏分为有参数和无参数两种。
1.无参数的宏
其定义格式如下:
1 | #define 宏名 字符串 |
在以上宏定义语句中,各部分的含义如下:
1 2 3 4 | #:表示这是一条预处理命令(凡是以“#”开始的均为预处理命令)。define:关键字“define”为宏定义命令。宏名:是一个标示符,必须符合C语言标示符的规定,一般以大写字母标示宏名。字符串:可以是常数,表达式,格式串等。在前面使用的符号常量的定义就是一个无参数宏定义。 |
Notice:预处理命令语句后面一般不会添加分号,如果在#define最后有分号,在宏替换时分号也将替换到源代码中去。在宏名和字符串之间可以有任意个空格。
1 | #define PI 3.14 |
它的作用是指定用标识符PI来代替“3.1415926”这个字符串,在编译预处理时,将程序中在该命令以后出现的所有的PI都用“3.1415926”代替。这种方法使用户能以一个简单的名字代替一个长的字符串,因此把这个标识符(名字)称为“宏名”,在预编译时将宏名替换成字符串的过程称为“宏展开”。# define 是宏定义命令。
【例1.1】不带参数的宏定义的应用。
程序代码:
#include<stdio.h>
#define PI3.1415926
main()
{
float l,s,r,v;
printf(“input radius: ”);
scanf(“%f”,&r);
l=2.0*PI*r;
s=PI * r * r;
v=3.0/4 * PI * r * r * r ;
printf(“l=%10.4f\ns=%10.4f\nv=%10.4f\n”,l,s,v);
}
在使用宏定义时,还需要注意以下几点:
1 2 3 4 5 6 7 8 9 | 宏定义是宏名来表示一个字符串,在宏展开时又以该字符串取代宏名。这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。宏名在源程序中若用引号括起来,则预处理程序不对其作宏替换。宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层替换。习惯上宏名可用大写字母表示,以方便与变量区别。但也允许用小写字母。 |
【例1.2】不带参数的宏定义的应用。
#include<stdio.h>
# define R 3.0
# define PI3.1415926
# define L 2 * PI * R
# define S PI * R * R
main()
{
printf(“L=%f\nS=%f\n”,L,S);
}
经过宏展开后,printf函数中的输出项L被展开为2 * 3.1415926 * 3.0,S展开为3.1415926 * 3.0 * 3.0,printf函数调用语句展开为
printf("l=%f\nS=%f\n",2 *3.1415926 *3.0,3.1415926 * 3.0 *3.0);
2带参数的宏
1 | #define命令定义宏时,还可以为宏设置参数。与函数中的参数类似,在宏定于中的参数为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,还要用实参去代换形参。 |
带参宏定义的一般形式为:
1 | #define 宏名(形参表) 字符串 |
在定义带参数的宏时,宏名和形参表之间不能有空格出现,否则,就将宏定义成为无参数形式,而导致程序出错。
1 | #define ABS(x) (x)<0?-(x):(x) |
以上的宏定义中,如果x的值小于0,则使用一元运算符(-)对其取负,得到正数。
带参的宏和带参的函数相似,但其本质是不同的。使用带参宏时,在预处理时将程序源代码替换到相应的位置,编译时得到完整的目标代码,而不进行函数调用,因此程序执行效率要高些。而函数调用只需要编译一次函数,代码量较少,一般情况下,对于简单的功能,可使用宏替换的形式来使用。
【例2.2】带参数的宏定义的应用
程序代码:
# define PI3.1415926
# define S(r)PI * r * r
main()
{
float a,area;
a=3.6;
area=S(a);
printf(“r=%f\narea=%f\n”,a,area);
}
运行结果:
赋值语句area=S(a);经宏展开后为
area=3.1415926 * a * a;
说明:
(1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。例12.3中语句中有S(a),在展开时,找到# define命令行中的S(r),将S(a)中的实参a代替宏定义中的字符串"PI* r * r"中的形参r,得到PI * a * a。这是容易理解而且不会发生什么问题的。但是,如果有以下语句:
area=S(a+b);
这时把实参a+b代替PI * r * r中的形参r,成为
area=PI * a + b * a + b;
请注意在a+b外面没有括号,显然这与程序设计者的原意不符。原意希望得到
area=PI * (a + b) * (a + b);
为了得到这个结果,应当在定义时,在字符串中的形式参数外面加一个括号。即
# define S (r) PI* (r) * (r)
在对S(a+b)进行宏展开时,将a+b代替r,就成了
PI * (a + b) *( a + b);
这就达到了目的。
(2) 宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。例如,如果有
# define S (r) PI * r * r
被认为S是符号常量(不带参的宏名),它代表字符串" (r) PI * r * r"。如果有
area=S (a)
被展开为
area=(r) PI * r * r (a)
显然不对了。

