10.1 宏定义
考点1 不带参数的宏定义
真考链接
此知识点简单,属于重点理解重点掌握知识点。该知识点在选择题中的考核概率为60%。
不带参数的宏定义命令行形式如下:
#define宏名 替换文本 或 #define宏名
在define宏名和宏替换文本之间要用空格隔开。
说明:宏名一般习惯用大写字母表示,宏替换的过程实质上是原样替换的过程。宏定义可以减少程序中重复输写某些字符串的工作量。
注意:可以用 #undef命令终止宏定义的作用域。
例如:
#define PI 3.14 -
main() ↑
{ PI的作用域
} ↓
#undef PI -
在进行宏定义时,可以引用已定义的宏名,例如:
#define R 15.5
#define PI 3.14
#define L 2*PI*R
小提示
使用宏定义过的常量,只要在定义常量处改变常量的值,则此常量在整个程序中的值都换成最新的值。
宏定义是用宏名代替一个字符串,也就是作简单的置换,不作语法检查。宏定义不是 C语句,不必在行末加分号。
#define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束可以用#undef命令终止宏定义的作用域。
真题精选
【例1】以下函数的功能是,通过键盘输入数据,为数组中的所有元素赋值。 在下划线处应填入的是( )。
#define N 10
void arrin(int x[N])
{ int i=0;while(i<N)
scanf("% d",______);
}
A.x+i B.&x[i+1] C.x+(i++) D.&x[ ++i]
【答案】C
【解析】本题考查了宏替换的知识,同时考查了自加的知识,因为要通过键盘输入数据,为数组中的所有元素赋值,所以下标要从0开始到9,只有选项C可以满足。
【例2】下面是对宏定义的描述,不正确的是( )。
A.宏不存在类型问题,宏名无类型,它的参数也无类型
B.宏替换不占用运行时间
C.宏替换时先求出实参表达式的值,然后代入形参运算求值
D.其实,宏替换只不过是字符替代而已
【答案】C
【解析】本例涉及宏替换的基本概念及与函数的简单比较,题目中的选项也确实是需要了解的一般知识。在本例中,宏替换的实质恰如选项D所言,是字符替代,因此,不会有什么类型,当然,就更不可能进行计算(C错误)。带参数的宏与函数相比,宏在程序编译之前已经将代码替换到程序内,执行时不会产生类似于函数调用的问题,可以说不占运行时间。
考点2 带参数的宏定义
真考链接
此知识点简单,属重点理解重点掌握内容。该知识点在选择题中的考核概率为70%。
定义的一般形式为:
#define宏名(参数表)字符串。
宏定义不只进行简单的字符串替换,还要进行参数替换,例如:
#define MV(x,y)((x)*(y))
…
a=MV(5,2);/* 引用带参数的宏名 */
b=6/MV(a+3,a);
以上宏定义命令行中,MV(x,y)称为“宏”,其中 MV是一个用户标识符,称为宏名。宏名和左括号“(”必须紧挨着,它们之间不能留有空格,其后圆括号中由称为形参的标识符组成,并且可以有多个形参,各参数之间用逗号隔开,“替换文本”中通常应该包含有形参。
执行过程:如果程序中有带实参的宏,则按#define命令行中指定的字符串从左到右进行替换。如果字符串中包含宏中的形参(如 x,y),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符(如(x*y)中的“*”号),则保留。这样就形成了替换的字符串。
带参数的宏和函数之间有一定类似之处,在引用函数时也是在函数右面的括号写实参,也要求实参与形参数目相等,但两者是不同的,主要表现在以下几个方面:
(1)函数调用时,要求实参、形参类型相匹配,但在宏替换中,对参数没有类型的要求。
(2)函数调用时,先求出实参表达式的值,然后代入形参,而使用带参数的宏只是进行简单的字符串替换。
(3)函数调用是在程序运行时处理的,要分配临时的内存单元,还要占用一系列的处理时间。宏替换在编译预处理时完成,因此,宏替换不占运行时间,不被分配内存单元,不进行值的传递,也没有“返回值”的概念。
(4)使用宏的次数较多时,宏展开后源程序变长,而函数调用不会。
小提示
与不带参数的宏定义相同,同一个宏名不能重复定义。在替换带参数的宏名时,圆括号必不可少。
常见问题
带参数的宏与函数有何异同点?
的确,带参数的宏与函数有一定的类似之处,在引用函数时也是在函数名后的括号内写实参,也要求实参与形参的数目相等。但是带参数的宏定义与函数是不同的:①函数调用时,先求出实参表达式的值,然后代入形参。而使用带参数的宏只是进行简单的字符替换。②函数调用是在程序运行时处理的,分配临时的内存单元。而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理。
真题精选
【例1】有以下程序:
#define N 2
#define M N+1
#define NUM(M+1)*M/2
#include <stdio.h>
main()
{ int i;
for(i=1;i< =NUM;i++);
printf("% d\n",i);
}
for循环执行的次数是( )。
A.5 B.6 C.8 D.9
【答案】C
【解析】程序中for循环的执行次数取决于NUM的值,因此正确地计算NUM的值是关键。在(M+1)*M/2中替换M。替换后为(N+1+1)*N+1/2;,然后替换N为(2+1+1)*2+1/2。这时可以根据其中的数字进行计算,得到4*2+1/2,计算的最后结果是8。
总结:切不可直接把值代入。例如,认为M的值是3,于是认为NUM是(3+1)*3/2,而得出错误的结果6。
【例2】以下程序的输出结果为( )。
#include <stdio.h>
#define SQR(x)x*x
main()
{
int a,k=3;
a= ++SQR(k+1);
printf("% d\n",a);
}
A.6 B.10 C.8 D.9
【答案】D
【解析】此题程序中定义了一个带参数的宏名为SQR,当程序中遇到此宏名进行展开时,则应使用定义时的字符串x*x进行替换。替换的原则是:遇到形参x,则以实参k+1代替,其他字符不变。所以,SQR(k+1)经宏展开后成为字符串k+1*k+1。整个赋值语句的形式变为a=++k+1*k+1;,k的值为3。若按从左到右的顺序运算,k先自增1,变为4,则a=4+1*4+1=9。