C语言宏函数(宏定义函数)的用法,非常详细
在C语言中,使用 #define 命令定义宏时可以带有参数,这点和函数比较类似,所以也被称为
在宏定义中出现的参数称为“形参”,在宏调用中出现的参数称为“实参”;宏函数在展开过程中不仅要进行文本替换,还要用实参去替换形参。
宏函数的定义格式如下:
宏定义是一种简单粗暴的文本替换,不会为参数分配内存,所以参数只有一个名字,不用为它指明类型。
宏函数的调用格式为:
可以使用宏来定义简单的函数,这些宏在调用时会被直接展开,而不会像普通函数那样产生调用开销(主要是数据的入栈和出栈)。
【示例1】一个简单的宏定义函数:
【示例2】稍微复杂一点的宏定义函数:
2) 宏函数不会为形参分配内存,因此不必指明数据类型。而在宏调用中,实参包含了具体的数据,要用它们去替换形参,因此实参必须要指明数据类型。
这一点和函数是不同的:在函数中,形参和实参是两个不同的变量,都有自己的作用域,调用时要把实参的值传递给形参;而在宏函数中,只是简单的文本替换,不存在值传递的问题。
例如:输入 n,输出 (n+1)^2 的值。
3) 在宏函数中,宏体内的形参通常要用括号包围起来,以避免出错。例如上例中的宏函数,((y)*(y)) 中的 y 都用括号包围,因此结果是正确的。如果去掉括号,把程序改为以下形式:
另外,只在参数两边加括号还是不够的,通常还要给整个宏体加括号。请看下面C语言代码:
由此可见,对于宏函数中的宏体,不仅要在形参两侧加括号,还要在整个宏体两侧也加括号。
宏函数
或者宏定义函数
;当然,你也可以直接叫它带参数的宏
或者带参宏
。在宏定义中出现的参数称为“形参”,在宏调用中出现的参数称为“实参”;宏函数在展开过程中不仅要进行文本替换,还要用实参去替换形参。
宏函数的定义格式如下:
#define 宏名(参数列表) (宏体)
其中,宏名
是我们给宏函数起的名字,参数列表
是宏函数接受的参数,宏体
则是宏展开后要替换的内容。需要注意的是,宏体
通常要用括号( )
包围起来(虽然不是必须的),以避免可能的运算符优先级问题。宏定义是一种简单粗暴的文本替换,不会为参数分配内存,所以参数只有一个名字,不用为它指明类型。
宏函数的调用格式为:
宏名(实参列表)
可以使用宏来定义简单的函数,这些宏在调用时会被直接展开,而不会像普通函数那样产生调用开销(主要是数据的入栈和出栈)。
【示例1】一个简单的宏定义函数:
#include <stdio.h> //定义宏函数 #define SQUARE(x) ((x) * (x)) int main() { int num = 5; int result = SQUARE(num); // 调用宏函数 printf("5 的平方是:%d\n", result); return 0; }运行结果:
5 的平方是:25
在这个例子中,SQUARE(x) 定义了一个计算平方的宏函数。当我们在代码中使用 SQUARE(num) 时,预处理器先用 num 替换宏体中的 x,然后再用处理过的宏体替换 SQUARE(num),最终的替换结果是:int result = ((num) * (num));
整个过程进行了两层替换。【示例2】稍微复杂一点的宏定义函数:
#include <stdio.h> #define MAX(a, b) ((a) > (b) ? (a) : (b)) int main() { int x = 10, y = 20; printf("x 和 y 中的较大值是:%d\n", MAX(x, y)); return 0; }运行结果:
x 和 y 中的较大值是:20
当我们在代码中调用 MAX(x, y) 时,预处理器会将其展开为 ((x) > (y) ? (x) : (y))。对宏函数的说明
1) 宏函数定义中,形参之间可以出现空格,但是宏名和形参列表之间不能出现空格。例如把:#define MAX(a,b) ((a>b)?a:b)写作:
#define MAX (a,b) ((a>b)?a:b)将被认为是无参宏定义,宏名 MAX 代表字符串
(a,b) ((a>b)?a:b)
。宏展开时,宏调用语句:
max = MAX(x,y);将变为:
max = (a,b) ((a>b)?a:b)(x,y);这显然是错误的。
2) 宏函数不会为形参分配内存,因此不必指明数据类型。而在宏调用中,实参包含了具体的数据,要用它们去替换形参,因此实参必须要指明数据类型。
这一点和函数是不同的:在函数中,形参和实参是两个不同的变量,都有自己的作用域,调用时要把实参的值传递给形参;而在宏函数中,只是简单的文本替换,不存在值传递的问题。
例如:输入 n,输出 (n+1)^2 的值。
#include <stdio.h> #define SQ(y) ((y)*(y)) int main(){ int a, sq; printf("input a number: "); scanf("%d", &a); sq = SQ(a+1); printf("sq=%d\n", sq); return 0; }运行结果:
input a number: 9↙
sq=100
sq = ((a+1)*(a+1));
你看,这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再传递给形参,而宏展开中对实参表达式不作计算,直接按照原样替换。3) 在宏函数中,宏体内的形参通常要用括号包围起来,以避免出错。例如上例中的宏函数,((y)*(y)) 中的 y 都用括号包围,因此结果是正确的。如果去掉括号,把程序改为以下形式:
#include <stdio.h> #define SQ(y) (y*y) int main(){ int a, sq; printf("input a number: "); scanf("%d", &a); sq = SQ(a+1); printf("sq=%d\n", sq); return 0; }运行结果为:
input a number: 9↙
sq=19
sq = (a+1*a+1);由于 a 为 9,所以 sq 的值为 19。这显然与本意相违,因此参数两边的括号是不能少的。
另外,只在参数两边加括号还是不够的,通常还要给整个宏体加括号。请看下面C语言代码:
#include <stdio.h> //宏体不加括号 #define SQ(y) (y)*(y) int main(){ int a,sq; printf("input a number: "); scanf("%d", &a); sq = 200 / SQ(a+1); printf("sq=%d\n", sq); return 0; }与前面的代码相比,只是把宏调用语句改为:
sq = 200/SQ(a+1);运行程序后,如果仍然输入 9,那么我们希望的结果为 2,但实际情况并非如此:
input a number: 9↙
sq=200
sq=200/(a+1)*(a+1);a 为 9 时,由于
/
和*
运算符优先级相同,并且都是左结合性,所以先计算 200/(a+1),结果为 20,再计算 20*(a+1),最后得到 200。由此可见,对于宏函数中的宏体,不仅要在形参两侧加括号,还要在整个宏体两侧也加括号。