宏和函数的区别
当我们通过学习C语言逐步理解了宏和函数的作用后,不免会产生这样的疑惑:宏和函数有什么区别?为什么有的代码在实现功能时用到的是宏,有的代码中却用到的是函数?
这里我以自己所学的知识总结了它们之间的区别,希望看到本文的小伙伴能够理解它们之间的区别,在以后使用的过程中能不出BUG,尽善尽美的完成代码编辑。
什么地方会用到宏?
就我们目前看到的这些代码来看,也有不少用到宏的地方,比如我在我的【浅谈】可变参数列表 这一文中提到的va_start,va_arg,va_end这三个宏,它们为什么要将他们写成宏而不是函数呢?
这里我要介绍宏对比函数一个最大的区别,就是宏的参数可以传递任意类型参数,甚至可以传递类型名,就我在【浅谈】可变参数列表 中提到的va_arg宏:
这个宏的第二个参数传递的就是int这个类型名,而如果换成函数的话,没有一个形参可以接收这个int类型吧?
下面我再给大家介绍宏对比函数第二个区别: 有时使用宏的效率会高于函数,大家没办法直接想到的话,不妨看一看下面的例子:
认识过栈帧的创建与销毁,相信大家应该对函数创建时的要执行的汇编语句都有点印象,那么想必大家也能想到函数在创建时不仅会在内存中创建一定的空间,而且会有传递和返回参数这么一个过程,它的效率必然是比宏要慢很多(因为宏作用时是在预编译阶段完成替换而已,并不会创建多余空间或是传递多余参数)。
那么说了这么多宏的优点,宏难道可以可以完全替代函数吗?
答案当然是 不能
宏传参时可能出现的副作用
如果你在使用宏是没有谨慎的规避,可能会使用到带有副作用的宏参数,比如:
i++
如果只提出这个参数带有副作用的话,相信大家会不服气,这里我给出一段代码,大家可以自己试一试,看看结果是不是自己预期的那样,为什么会出现与预期结果不一样的情况?
#define MIN(A, B) (A < B ? A : B)
int a = 10;
int b = 20;
int ret = MIN(a++, b++);
printf("%d %d %d\n", a, b, ret);
而这样的代码,又能否得到预期的结果呢?
#define COUNT(A, B) (A * B + B)
int a = 10;
int b = 20;
int ret = COUNT(a+b, a+b);
printf("%d\n", ret);
总结
对于宏可能出现的副作用,建议对宏内的参数多加括号:
#define COUNT(A, B) ((A) * (B) + (B))
int a = 10;
int b = 20;
int ret = COUNT(a+b, a+b);
printf("%d\n", ret);
鉴于宏参数的副作用,建议谨慎使用宏,或者避免使用宏。