C++_inline函数(内联函数)浅析

内联函数

在C++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别地引入了inline修饰符,表示为内联函数。
如下简单示例:

inline int Max(int a, int b)
{
    
    
	return a + b;
}

处理方式

内联函数的处理方式是在函数的调用点直接代码展开。在计算机系统下,如果频繁的调用会造成较大的时间开销。内联函数的引入减少了函数调用过程中开栈和清栈的开销。
处理流程如下图所示:
在这里插入图片描述

左图普通函数的调用点,函数的处理流程:

先进行实参压栈然后处理函数体;

右图内联函数的调用点,函数的处理流程:

函数没有开栈和清栈,函数体直接在调用点代码展开。

内联函数与普通函数的区别

  • 内联函数在调用点代码直接展开,没有开栈和清栈的开销。普通函数有开栈和清栈的开销;
  • 内联函数要求代码简单,不能包含复杂的结构控制语句;
  • 如果内联函数体过于复杂,编译器将自动把内联函数当成普通函数来执行。

内联函数与static修饰的函数的区别

  • static修饰的函数只是将函数的符号变成局部符号,函数的处理机制与普通函数相同,都有函数的开栈和清栈开销;内联函数没有函数的开栈和清栈开销;
  • inline函数是因为代码在调用点直接展开导致函数本文件可见;而static修饰的函数是因为函数符号从全局符号变成局部符号导致函数本文件可见。

内联函数与宏的区别

  • inline函数的处理时机是在编译阶段处理的,有安全检查和类型检查;而宏的处理是在预编译阶段处理的,没有任何的检查机制,只是简单的文本替换
  • inline函数是一种更安全的宏。

使用场景

说了这么多,我们心里可能会产生疑问,既然内联函数这么好,为什么不把所有的函数都设计成内联函数呢?
内联函数的缺点?
inline函数也不是十全十美的。如果一个项目下存在多个inline函数的调用点。每个调用点都要将代码直接展开,那么将会导致目标文件非常庞大。所以,内联函数是以代码膨胀为代价的:典型的以空间来换时间的概念来设计的。
什么时候使用内联函数呢?

  • 如果函数的执行开销小于开栈清栈开销,使用内联函数处理:此时,函数体较小,处理效率高;
  • 如果函数的执行开销大于开栈清栈开销,使用普通函数处理:此时函数体较大,空间利用率较高。

注:特别是函数的执行开销远远大于开栈清栈开销,这种情况下函数的开栈和清栈开销可以忽略不计,使用普通函数最合适。

汇编层次内联的处理

下面我们从汇编的层次来看看内联函数的处理:
在这里插入图片描述
可以看到:
汇编层次的内联函数调用,明显是以实参压栈的方式来处理的,有开栈和清栈的开销产生。
这和我们上面讲的不就冲突了吗?这是为什么呢?
其实 inline 函数也有一些限制:

  • inline 函数一般写在头文件中;
  • inline 函数只在 Release 版本生效,在 Debug 版本不生效;
  • inline 函数只是给编译器的一个建议,具体是否执行还要由编译器来决定。它是基于实现的,而不是基于声明。

我们可以看到百度百科上给出的内联函数的定义:

在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展)。在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展)。

这下就很好理解了,他只是一个建议,具体实现还要看编译器。

参考资料

【1】内联函数(百度百科)

猜你喜欢

转载自blog.csdn.net/m0_46308273/article/details/113751150
今日推荐