题记,你知道的编程语言中有哪些类型的函数呢?如果你学过C++的,你知道内联函数吗?这个优秀又隐蔽的存在,本文将带你初步了解一下内联函数。
系列文章
C++编程之命名空间、const常量
C++编程之引用的详细总结
C++中引用的本质到底是什么?
C++中类的构造函数和析构函数(一)
C++编程之运算符重载
常规函数
在程序的运行中,函数调用时,程序会跳到另一个地址(函数地址)中,执行到函数调用指令时,程序将在函数调用后存储该指令的内存地址,并将函数参数复制到堆栈中,跳到标记函数起点的内存单元,执行函数代码(可能还需要将返回值放入寄存器中),然后跳回到地址被保存的指令处。这样来回跳跃以及入栈等频繁操作,会消耗系统内存,增加系统开销。因此在C/C++中,一般将短小精悍的函数写成宏函数。
宏函数
一般建议将短小、频繁使用的函数封装成宏函数,调用时,直接宏展开,跑源码,减少入栈出栈的系统开销。
#define ADD(x,y) x+y
int main()
{
int a = 100;
int b = 200;
int c = ADD(a+b);
// c=300
}
但是宏函数还是有很多缺陷,比如:
int ret = ADD(10 + 20) * 20;
// 按照常识一般是600,但运行结果其实是410.因为宏展开是这样的 10+20*20 按照运算符优先级,计算出是410
那如何避免如上问题呢?最简单的办法是在每个操作符之间加入括号。
但是如下示例,比较两个数的大小,我们使用宏函数表示,每个该加括号的地方都加入括号
#define MyCompare(a,b) (((a)<(b))?(a):(b))
// 调用
int a=10;
int b=20;
MyCompare(a,b); // 正常
MyCompare(++a,b); //应该是多少呢?结果令人吃惊,居然是12.原因是宏展开后(((++a)<(b)?(++a):(b))),即发生了2次++。
同样示例如下
#define Square(x)(x)*(x)
int main()
{
int a = 10;
int b = Square(++a); // 结果不是预期
}
因此,总结以下宏函数的缺点:
- 运算完整性无法保证,需要加小括号;
- 即使加入括号修饰符,有些情况依然会出现和预期不一样的结果
- 宏函数不重视作用域
基于以上缺点,在C++中引入了一个新的函数,那就是内联函数。
内联函数
内联函数具有普通函数的所有特性,但是还具有在适当的时候内类似宏展开,不会有入栈出栈的系统开销。
内联函数定义如下
inline int MyCompare(int a,int b)
{
return a>b?a:b;
}
注意点:
- 函数的声明和实现必须同时加inline关键字,否则会按照普通方式处理
// TestInline.h
inline int MyCompare(int a, int b);
// TestInline.cpp
inline int MyCompare(int a, int b)
{
return a > b ? a : b;
}
- 成员函数的前面隐藏的加了inline。
- 内联函数实现了空间换时间,提高效率。
说到这里,很多人可能会想,既然这么好,那我以后所有的函数都写内联函数,那我要遗憾的告诉你,这就错了!!!
内联函数并不是一直都有效的,还要看编译器的心情。以下情况编译器可能不考虑:
- 不能有任何形式的循环
- 不能存在过多的条件判断语句
- 函数体不能过于庞大
- 不能对函数进行取址操作
内联仅仅是给编译器的一个建议,编译器不一定会按照你的建议,如果你没将函数声明为内联函数,编译器可能会给你设置为inline,好的编译器会自动将一些频繁调用短小的函数自动设置为内联函数。