C++内联函数

什么是内联函数

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

为什么存在内联函数

我们知道,普通的函数需要建立栈帧空间

因此,可以利用宏来定义一些小的函数(行数较少的)

这样,函数调用的时候其实就是语句的直接替换,而不存在函数栈帧的创建和销毁

比如,一个实现两个数相加的函数

//普通函数
int Add(int x,int y)
{
    return x+y;
}
//宏函数形式
#define ADD(a,b) ((a)+(b))

对比于普通函数来说,宏的优点就很明显了

  • 使用宏函数,可以不用建立栈帧,减小系统开销,提高运行效率

但是显然,宏也有缺点

  1. 相比于函数,宏定义的函数可读性差,函数体复杂
  2. 宏函数参数没有类型检查,容易出现bug(如不同类型的相加)
  3. 宏在预处理阶段就直接整体替换展开了,不方便调试

所以,为什么存在内联函数?

内联函数的存在就是为了解决宏的缺点,同时保留宏的优点

内联函数的查看

既然你说,内联函数不会调用函数,直接展开

有什么证据呢?

如图所示,这是没有加inline修饰的函数

可以看到反汇编中存在call Add这条命令,也就是会调用函数

image

但是如果加了inline修饰呢?

注意

  • 如果在release模式下,查看汇编代码中是否存在call Add即可
  • 但是如果在debug模式,需要进行设置,因为inline属于一种优化,debug模式下为了方便调试默认不会进行优化

以VS2019为例,关闭优化:

image

image

可以看到,关闭优化之后,执行到Add函数的时候,并没有执行优化

说明inline是存在的

内联的注意事项

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用

    缺陷:可能会使目标文件变大

    优势:少了调用开销,提高程序运行效率

  2. inline对于编译器只是一个建议,不同编译器关于inline实现机制可能不同

    一般函数规模较小(展开汇编 小于10行),没有递归。并且会频繁调用的函数,编译器会采纳inline的建议。否则编译器会忽略inline的建议。因为如果展开汇编代码很多的话,会导致程序的大小变大!

    比如:

    如果一个函数有100行,调用10000次
    比较程序的语句数量
    不展开:10000个call + 100 个指令
    展开:100*10000 条指令 
    可执行程序会明显变大
    

    而可执行程序变大的结果就是:

    比如更新《王者荣耀》这个游戏,500MB的更新内容硬是要更新2个G,难受不难受😫

    如《C++primer》中所述

image

  1. inline的声明和定义不要分离,如果在.h中声明inline func(),然后在test.cpp中进行定义,main.cpp中进行调用。那么当调用的时候,因为有头文件所以编译可以通过.但是链接的时候,就去test.cpp生成的目标文件的符号表中去找函数的地址(call动作),但是由于func()inline修饰的,所以编译器并不会把函数的地址放入符号表,所以就会出现链接错误

如果函数用inline属性修饰,那么编译器统一不会把该函数的信息放到符号表

所以内联函数一般是在.h中直接定义的,或者在需要调用的本.cpp文件中定义

posted @ 2024-01-22 16:43  夏季微凉"  阅读(61)  评论(0编辑  收藏  举报