首页 > 编程语言 >【C++】内联函数

【C++】内联函数

时间:2024-07-18 20:27:26浏览次数:14  
标签:函数 查看 int C++ 反汇编 inline 内联

目录

前言

各位友友好,我们又见面了!本节我们将进入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 函数的反汇编了。

结尾

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

标签:函数,查看,int,C++,反汇编,inline,内联
From: https://blog.csdn.net/2302_79341182/article/details/140397225

相关文章

  • GESP编程能力等级认证C++编程真题解析 | 2024年3月五级
    学习C++从娃娃抓起!记录下CCF-GESP备考学习过程中的题目,记录每一个瞬间。附上汇总贴:GESP编程能力等级认证C++编程真题解析|汇总单选题第1题唯一分解定理描述的内容是()?A.任意整数都可以分解为素数的乘积B.每个合数都可以唯一分解为一系列素数的乘积C.两个不同的......
  • Z 函数(扩展KMP)
    author:LeoJacob,Marcythm,minghu6约定:字符串下标以\(0\)为起点。定义对于一个长度为\(n\)的字符串\(s\),定义函数\(z[i]\)表示\(s\)和\(s[i,n-1]\)(即以\(s[i]\)开头的后缀)的最长公共前缀(LCP)的长度,则\(z\)被称为\(s\)的Z函数。特别地,\(z[0]=0\)。国外一......
  • 白骑士的C++教学实战项目篇 4.3 多线程网络服务器
    系列目录上一篇:白骑士的C++教学实战项目篇4.2学生成绩管理系统        在这一节中,我们将实现一个多线程网络服务器项目,通过该项目,我们将学习套接字编程的基础知识以及如何使用多线程处理并发连接。此外,我们还将实现一个简单的客户端来与服务器进行通信。项目简介......
  • c++ primer plus 第16章string 类和标准模板库,16.2.1 使用智能指针
    c++primerplus第16章string类和标准模板库,16.2.1使用智能指针c++primerplus第16章string类和标准模板库,16.2.1使用智能指针文章目录c++primerplus第16章string类和标准模板库,16.2.1使用智能指针16.2.3uniqueptr为何优于autoptr16.2.3unique......
  • c++ primer plus 第16章string 类和标准模板库,16.2.2 有关智能指针的注意事项
    c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项文章目录c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项16.2.2有关智能指针的......
  • 嵌入式学习——C语言字符数组及其函数
    目录一、字符数组    1、定义    2、初始化                    3、引用字符数组元素二、字符串和字符串结束的标志三、字符数组的输入输出        1、字符串的输入:scanf    2、注意事项四、字符串处理函数......
  • 第八章函数及常用的内置函数
    函数的定义和调用1、内置函数:输出函数print()输入函数input()列表定义的函数list()2、自定义函数def函数名称(参数列表):函数体[return返回值列表]3、函数调用函数名(参数列表)不带返回值的函数直接调用,带返回值的函数调用后要将结果保存到变量中点击查看......
  • C++ 面向对象程序设计 ---- 类2重点
    1.构造函数,代替Init()函数构造函数的特点1.函数名与类名相同2.无返回值,void也不需要写3.对象实例化时,系统会自动调用构造函数4.构造函数可以重载classDate{public://函数名与类名相同,无返回值Date()//函数重载,无参{_year=1;......
  • 扩展 KMP/exKMP(Z 函数)学习笔记
    声明本文章转载自shangruolin的博客,已经过作者(存疑)同意,帮TA宣传一下。扩展KMP/exKMP(Z函数)学习笔记兼P10479匹配统计题解。LCP:最长公共前缀。Z函数,又称扩展KMP(exKMP),能够在\(O(n)\)的时间内求出一个字符串与其所有后缀的LCP的长度。定义\(z_i\)为字符串\(s\)......
  • 【算法】JZ30 包含min函数的栈
    1.概述描述定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,输入操作时保证pop、top和min函数操作时,栈中一定有元素。此栈包含的方法有:push(value):将value压入栈中pop():弹出栈顶元素top():获取栈顶元素min():获取栈中最小元素......