【C++】内联函数

前言

各位友友好,我们又见面了!本节我们将进入C++基础之内联函数的学习,这节小编会从不同的角度给大家介绍内联函数的概念及特征。下面我们正式开始。

一、内联函数的概念

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

使用方法:在函数前加上 inline 即可,例如 : inline int Add(int left,int right){ }

下面我们来看一段代码并查看其反汇编(这里小编直接给出 debug 模式 下代码的反汇编,大家也可以自行去VS查看,下面也会附上查看反汇编的方法):

图1图2

说明:第一张图是 VS 2022 的反汇编图,第二张图是旧版 VS 2013 的反汇编图

解释: 我们看第一张图汇编的第一第二行,这里把值 2,1 分别传给了 edx, ecx ( edx,ecx 是通用寄存器,保留临时数据,mov 即是赋值的指令),这里的传值即是一个传参的过程,现在为了效率更快,就把值直接传给了寄存器进行存取;( vs2013 是把值压进栈区进行存取,即传值是一个压栈的过程,如第二张图的 push );即我们调用这个函数的过程是先把 2 传给 edx,再把 1 传给 ecx,然后再去调 Add 这个函数 (即汇编的第三行,call Add );我们都知道,调用函数是要建立栈帧的,而建立栈帧是有消耗的(函数栈帧图可看下图)。 (建立栈帧和销毁都是有消耗的)

在这里插入图片描述
我们再来举一个形象的例子,例如我们平时所写的 void Swap (int& a , int& b ){ int tmp = a ; a = b ; b=tmp} 这个函数,这个函数很简单,就三行代码,但是我们很多地方都有用到 Swap 函数(冒泡排序,插入排序,快速排序等等),这些地方我们都要调用这个函数,但是调用这个函数又有开销,要建立栈帧,造成了很多效率的损失。
那么有什么办法可以解决这个问题呢?(频繁调用 Swap 是有消耗的)
1.在C语言中:使用宏函数

宏函数的好处:宏函数在预处理阶段的时候在调用函数的地方把函数展开了,展开以后就没有建立栈帧、压栈、销毁之类的开销了。
但是宏函数也有很多缺点;如:可读性比较差,不能调试等等。

2.在C++中:使用内联函数(在函数前面加上 inline ,加上之后函数就会在调用它的地方展开,当然你也可以每次在调用的地方写一个这样的函数,这样也没有调用函数,但是每次都去写是不是超级麻烦,所以 inline 展开就相当于帮你完成了每次都去写的这个步骤)

如果我们在上述函数前增加 inline 关键字将其改成内联函数,那么在编译期间编译器就会用函数体替换函数调用,这样我们就可以减少消耗辣!我们来看看加了 inline 之后的汇编(注意:vs 在debug 模式下查看 inline 的汇编需要调整配置,方法我们会放到文章最后,这里直接看小编的截图)
在这里插入图片描述
这里我们可以看到并没有函数的调用(没有 call Add), 而是在调用这个函数的地方直接实现了 1 + 2(即 left + right ;:在调用的地方展开了),这样就减少了调用函数的开销,提高了效率。
但是内联函数也不是什么时候都适合用的,下面我们来看看他的特征吧!

二、内联函数的特征

1、 inline是一种以空间换时间的做法,可以省去调用函数的开销。但是代码很长或者有循环/递归的函数不适宜
使用作为内联函数。一般内联适用于小函数(即小于20行代码左右的函数)。
2、 inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内代码比较长或者有递归等等,编译器优化时会忽略掉内联(不会展开)
3、inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会
找不到。(内联函数没有地址),例如下面代码:

//F.h    //头文件
#include<iostream>
using namesapace std;

inline void f(int i);//函数的声明
--------------------------------------------------------------------
//F.cpp
#include"F.h"
void f(int i)[     //函数的定义
    cout << i << endl;
}

//main.cpp
#include"F.h"
int main(){
    f(10);
    return 0;
}

//编译时出现的链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?
//f@@YAXH@Z),该符号在函数 _main 中被引用

三、总结:

宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?
1.常量定义 换用const 。 (例: #define N 10const int N = 10 来替代)
2. 函数定义 换用内联函数。

四、如何在 vs2022 查看反汇编以及 debug 模式下查看 inline 反汇编需要调整的配置。

4.1 查看反汇编

方法1:键盘按下 F10 (有些笔记本是Fn + F10),使程序进入调试状态;然后鼠标移动到想要查看汇编的那一行代码,右击鼠标,选择转到反汇编,并点击它即可。
方法2:键盘按下 F10 ,使程序进入调试状态;然后鼠标点击电脑最上面的调试(D);然后再选择窗口,然后选择反汇编即可。如下图:
在这里插入图片描述

4.1 debug 模式下查看 inline 反汇编需要调整的配置

1.首先点击电脑最上面的调试(D) ,然后点击最下面的调试属性,然后展开 C/C++ 那一项,点击常规 -> 调试信息格式(改成 程序数据库(/Zi))。如下图:
在这里插入图片描述

2.再点击优化->内联函数扩展(改成:只适用于_inline(/ ob1),然后点击应用即可。如下图:
在这里插入图片描述
完成以上操作就能查看 dedug 模式下 inline 函数的反汇编了。

结尾

以上即为本节的所有内容辣!喜欢的友友们记得点赞评论加收藏哦,小编会努力给大家更新更精彩的内容的!

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值