欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

带参数的宏定义、函数与内联函数

程序员文章站 2024-03-21 10:08:40
...


前言

在实际项目开发,尤其是嵌入式软件项目中,经常可以看到大量宏定义的分布,其中又多以带参数的宏定义为主。对于刚入门的小白来说,这可能也算是C语言的高级用法之一。当然,它的用处也确实相当广泛。
带参数的宏,它的功能类似于函数。在多数场景当中,它的目的也是旨在能够一定程度上取代部分的函数调用。
以上两种方式并存,但各自都有优缺点,也因此,inline函数诞生。它可以说是兼具了函数和带参数的宏定义优缺点于一身的产物。


“存在即合理” --黑格尔《法哲学原理》

一、宏定义

1.基本用法

在预编译过程中无条件文本替换:

#include<stdio.h>

#define OKAY			0
#define OVERFLOW		1
#define UNDERFLOW		2
#define MAX				10
#define MIN				5

void main()
{
	unsigned char InputVal	= 0;
	unsigned char Result	= OKAY;

	printf("Inpue a new value please: ");
	scanf("%d", &InputVal);

	if( MAX < InputVal ){
		Result = OVERFLOW;
		printf("The input is OverFlow !\n");
	} else if( MIN > InputVal  ){
		Result = UNDERFLOW;
		printf("The input is UnderFlow !\n");
	}else{}
}

在预编译之后,文件中所有出现的宏定义,将分别被对应的数值替代,如,代码中出现MAX 的地方,被10取代,MIN被5取代。

2.带参数的宏定义

以下为一个经典的判断最值的例子:

#define MAX(a,b) ((a)>(b)?(a) : (b))

如果代码中有如下“调用”语句:

int c=MAX(5,3);

编译器预处理后,代码被替换为:

int c=((5)>(3)?(5) : (3));

不难看出,宏定义的使用,无论是否带有参数,其实就是一个纯粹的文本替换的过程。它的出现,在一定程度上,增强开发者或者后续维护者的交互体验,毕竟对于人类来说文字描述更容易理解。但是,它的劣势也是显而易见的:代码量的增加。毕竟再小规模的宏定义,替换的地方越多,也就意味着代码量的膨胀。
宏定义还有一个优势,即“一改全改”,不用查找文件中的所有引用逐一进行修改,只需要需改宏定义不分即可。当然,这也可能带来另一个致命的缺陷:一旦宏定义不准确,错误将是全局性的。

二、函数

1.定义与声明

int Func_Max(int a, int b)
{
	if(a > b)
		return a;
	return b;
} 

2.调用

int c=Func_Max(5,3);

不难看出,c的值为5,函数Func_Max同样能实现以上宏定义MAX的功能,只不过,实现的过程有一定差异:

  1. 首先,函数是通过其函数指针进行调用的,不会进行代码文本的替换,因此代码量不会有过多的冗余产生;
  2. 函数在执行之前,首先会对返回值和参数列表进行安全性检查,并在调用时为它们分配一定的堆栈空间进行参数的暂存。

三、内联函数–inline

像static、extern 等一样,inline是C++中的一个关键词,可用于修饰函数和C++中类的成员函数:

inline int Func_Max(int a, int b)`
  1. inline定义的内联函数,函数的代码被放入符号表中,在使用时直接进行替换(像宏一样展开),没有了调用时堆栈资源的开销,效率也很高。
  2. 很明显,类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。

总结

函数、宏定义各自都有着自己的独特性,在自己的应用场景下,有着举足轻重的作用,不能说不能替代,但是替代之前也需要再三思量。inline函数算是二者的子系,它囊括了函数和宏定义的几乎所有的特点,无论是优点还是缺点,它的使用看似常规,快捷,但也暗藏杀机。当然,如果数量掌握了其用法,就另当别论了。