宏和函数的区别

1、执行速度(效率)

 #define 宏 的执行速度快,而函数由于存在函数调用以及函数返回时的额外开销,因此函数的执行速度慢一些。通俗点来讲,就是#define 宏在程序运行过程中,只执行逻辑部分。而函数需要做一些准备工作,比如调用函数前要先在栈中预开辟一片空间,调用函数时执行逻辑部分,并且会保存调用函数的地址,函数调用结束后根据保存的地址返回到之前函数调用的地方,显然,#define 宏的执行速度快一些。

2、调试

#define 宏 不便于调试,编译报错时,往往编译器报错的地方并不是真正发生错误的地方,而函数调试是比较方便的。这是因为#define 宏是在编译时的预处理阶段就被编译器处理了,只完成一些替换操作,而函数是在程序运行过程中被处理的。

3、代码长度

在编译的预处理阶段,#define 宏 会被替换掉,假如宏定义特别多,那么会使得代码长度大幅度增加,而函数只有在调用时才会使用定义函数的代码,并且函数调用结束后会释放掉调用期间开辟的空间,这并不会影响代码的长度。

4、参数类型

#define 宏 与类型无关,也就是说,宏可以用于任何操作合法的参数类型,而函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,并且,函数传参是不可以传入数据类型的。

# include <malloc.h>
# define MALLOC(NUM, TYPE) (TYPE *)malloc(NUM * sizeof(TYPE))  //宏在传参时是可以传入类型的
 
int max = 0;
max = Max(x, int, y, int);  //error 函数在传参时是不可以传入数据类型的

5、操作符的优先级

#define 宏 参数的求值需要给参数加上相应的括号,否则邻近操作符可能会影响所求值的结果,这是因为宏只是做了简单的替换操作。而函数的参数只在函数调用时求值一次,并将结果传递给函数即可。

# include <stdio.h>
# define SQUARE(X) X*X
 
int main(void)
{
	int ret = 0;
	
	ret = SQUARE(3 + 1);
 
	printf("square = %d\n", ret);
 
	return 0;
}

在这里插入图片描述

我们期待的结果是44=16,而运行上述程序的结果却是7,这是因为宏只是做了简单的替换,因此可以得到替换后的结果为:3+13+1=7。

假如想要得到结果16,我们可以通过加上括号的方式来解决:

# include <stdio.h>
# define SQUARE(X) ((X)*(X))
 
int main(void)
{
	int ret = 0;
	
	ret = SQUARE(3 + 1);
 
	printf("square = %d\n", ret);
 
	return 0;
}

在这里插入图片描述

函数在调用时先将参数计算一次,然后将结果传给函数。

# include <stdio.h>
 
int Square(int x)
{
	return x * x;
}
 
int main(void)
{
	int ret = 0;
	
	ret = Square(3 + 1);
 
	printf("square = %d\n", ret);
 
	return 0;
}

在这里插入图片描述

6、参数求值

#define 宏 参数每次用于宏定义时,都将重新求值,这样带有副作用的宏参数就可能会使得计算结果出错,而函数的参数只在函数调用时求值一次,之后的多次函数调用中都不会改变其值。

先来看下这段代码:

# include <stdio.h>
# define MAX(x, y) ((x) > (y) ? (x) : (y))
 
int main(void)
{
	int x = 2;
	int y = 5;
	int ret = MAX(x++, y++);
 
	printf("x = %d\ty = %d\tret = %d\n", x, y, ret);
 
	return 0;
}

在这里插入图片描述
以上就是宏参数对宏产生的副作用,首先展开宏参数可以得到(x++)>(y++)?(x++):(y++),由于是后置++,因此先给x,y赋值,此时x=2,y=5,显然2<5,将执行:后面的语句,此时x自增1,变成3,y自增1变成6,而?后面的语句不被执行,x最终的值就是3。在执行:后面的语句时,y为6,同样的后置++,把6赋给该语句,此时ret的值就是6,最后y自增1得到7。

再来看看下面这段代码:

# include <stdio.h>
 
int Max(int x, int y)
{
	return x > y ? x : y;
}
 
int main(void)
{
	int x = 2;
	int y = 5;
	int ret = Max(x++, y++);
 
	printf("x = %d\ty = %d\tret = %d\n", x, y, ret);
 
	return 0;
}

在这里插入图片描述
调用函数Max时,将参数x++,y++传进去,由于后置++,因此先赋值后自增,传给函数的值是x=2,y=5,经过比较后返回5给函数,函数调用结束后x,y分别自增1,x变为3,y变为6。

因此,我们应该尽量避免使用带有副作用的宏参数。

综上所述,我们发现,宏和函数相比,有优势,也有劣势。那么是否有一种方法既可以替代宏,又可以替代函数呢?答案是肯定的,那就是内联函数(ps:inline)。它接收数据类型的检查,并且可以像宏那样展开,还可以像函数一样被调试。

总结下几种替换宏的方式:

  1.C++中用const来代替宏常量;

  2.使用inline来代替宏函数(包含类型检测);

  3.使用typedef来代替define定义的类型;

  4.使用enum来代替定义多个宏常量,并且enum定义的常量可读性更高。

下面是对宏和
函数区别的总结

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值