对于一个频繁使用的短小函数,在C语言和C++中分别应用什么实现?
C语言通常使用预处理的宏定义#define来代替短函数定义,而C++使用inline内联函数。
宏定义#define代替短函数可能出现的问题,举例说明。
对于#define MAX(a, b) ((a) > (b)?(a):(b))
这样一个宏定义,即使我们非常谨慎将所有参数都放在了括号内,但仍然会出些类似以下情况的麻烦:
int a = 1, b = 0;
MAX(a++, b); // 此处被替换成((a++) > (b)?(a++):(b)),a自增了两次
cout << a << " " << endl;
MAX(a++, b+10); // 此处由于前者小于后者,因此a自增了1次
// 此外,对于不同类型数据的比较也没有受到函数调用的类型检查
MAX(a, "Hello")
由此可见,以上这个宏定义是有一些问题的,同普通函数的功能还是有一些差距。如果是普通函数,在比较不同类型数据使还会受到函数调用的类型检查。
为什么要引入内联函数?
引入内联函数是为了提高程序执行的效率。
对于C/C++程序中一个普通函数的调用过程实际上是将程序执行顺序转移到函数所在的内存中某个地址,将该地址的函数程序执行完成之后,再返回转入函数地址之前的内存地址继续执行之后的代码,这一程序执行转移过程就意味着需要在转去函数所在内存地址前保护程序执行现场并记忆当前程序的内存地址,从函数所在内存地址转回后恢复现场并按照记忆地址继续执行。
从以上过程分析可得,普通函数的调用需要有一定时间和空间方面的开销,这将影响程序执行的效率。尤其对于一些低代码量但被高频调用的函数体,时空开销在整个跳转过程中占有较大的比例,因此针对这一类函数,解决其效率问题非常重要。
内联函数在很大程度上解决了这个问题,程序编译时,在编译阶段将调用内联函数的表达式直接进行展开。这种办法将不会产生程序执行跳转的问题,减少了跳转的时间开销;但函数表达式展开将会增加目标程序代码量,进而增加空间开销。由此可见,内联函数的使用是以空间换时间的做法,对于短函数而言较小的空间开销换取内存地址频繁跳转的时间开销是值得的。
内联函数与宏定义的区别
- 内联函数在编译时展开,宏定义在预编译阶段展开;
- 内联函数是函数体嵌入到目标代码中,宏定义是直接做字符串替换;
- 内联函数有类型检查等功能而宏定义没有;
内联函数的使用
所有在类的声明中定义的函数将被自动认为是内联函数。
在内联函数中若有循环和递归调用等复杂操作将不被内联。
求点赞!求收藏!求关注!( •̀ ω •́ )✧