C++内联函数:那时我还太年轻,并不知道使用inline带来的效率,早已在暗中标好了价格

本文主要是介绍C++内联函数:那时我还太年轻,并不知道使用inline带来的效率,早已在暗中标好了价格,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

  • 👑专栏内容:C++学习笔记
  • ⛪个人主页:子夜的星的主页
  • 💕座右铭:日拱一卒,功不唐捐

文章目录

  • 一、前言
  • 二、内联函数
    • 1、起源
    • 2、概念
  • 三、与宏的区别
    • 1、宏的缺点
    • 2、两者区别
  • 四、内联函数的代价
    • 代价一:可执行程序变大
    • 代价二:`inline`可能被忽略
    • 代价三:声明和定义不可分离
  • 五、总结


一、前言

关键字inline是C++相对于C语言的又一个扩充,在函数的声明或定义、函数的返回类型前加上关键字inline,即可把函数指定为内联函数从而提升程序运行的效率。但使用inline是要付出代价的,正如茨威格在《断头王后》中那样写道:“ 那时候她还太年轻,不知道所有命运馈赠的礼物,早已在暗中标好了价格。” 那么inline的优势和它为此要付出的代价是什么呢?让我们来慢慢揭晓!

二、内联函数

1、起源

当一个函数被调用执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址放入栈中,最后才跳转到函数内部执行。这个过程是要消耗时间和栈空间(放置函数内数据的内存空间)的。当一个函数非常短小,但由于被放入循环体中大量的循环,就会消耗大量的时间。同时由于栈空间是有限,所以频繁大量的使用也会造成因栈空间不足所造成的出错。
在这里插入图片描述

2、概念

内联函数是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展;也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。在C++中在一个函数的前面加上inline进行修饰,就会将这个函数变为内联函数。
在这里插入图片描述
小C挑衅大哥也不是一天两天了,本着 能打就打 以理服人的做法。接下来我们就举个例子现场回应他的挑衅。

int Add(int left,int right)
{return left + right;
}
int main ()
{int ret = 0;ret = Add(1,2);return 0;
}

接着,我们点住ret查看其汇编代码。
在这里插入图片描述
我们可以看到,ret的汇编代码中,有一句的前面有一个call,在汇编语言中call就是函数调用指令。它的作用就是将程序当前执行的位置IP压入堆栈中,转移到调用的子程序。
接下来。我们在刚刚的函数前面加入inline进行修饰,再看其汇编语言。

inline int Add(int left,int right)
{return left + right;
}
int main ()
{int ret = 0;ret = Add(1,2);return 0;
}

在这里插入图片描述
哇,汇编代码中的call果然消失不见了呢~
那接下来该干嘛了?当然是以理服人!

在这里插入图片描述

三、与宏的区别

C语言中确实也有不建立栈帧的方法,那就是使用宏来定义函数。

在这里插入图片描述

#define Add(int x,int y) return x+y;

呀…写错了,我重写!

#define Add(x,y) x+y;

额…又错了!再给一次机会!

#define Add(x,y) (x)+(y)

呜…失误!再再给我一次机会!

#define Add(x,y)((x)+(y))

哇…终于写对了!!!!
在这里插入图片描述

1、宏的缺点

宏其实是一种非常暴力的替换,正因为如此,它的缺点有很多:

  1. 宏函数不能进行调试。
  2. 宏函数不会进行类型的检测,代码安全性低。
  3. 宏函数容易产生二义性,可维护性差。
  4. 宏函数的编写容易出现错误。

2、两者区别

  1. 内联函数是在编译时展开,而宏在预编译时展开。
  2. 在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。
  3. 内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。

四、内联函数的代价

在这里插入图片描述

代价一:可执行程序变大

inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
用函数体替换函数调用,这样就会导致编译出来的可执行程序变大。

代价二:inline可能被忽略

inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同。
一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
《C++prime》第五版关于inline的建议:
在这里插入图片描述

代价三:声明和定义不可分离

定义和声明分离的后果是什么?以下面的代码为例:

F.h
#include <iostream>
using namespace 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;
}

运行结果:
在这里插入图片描述
为什么普通函数可以将定义和声明分离,而内联函数不行呢?
在这里插入图片描述
看汇编代码,普通函数会产生跳转时对应的地址。而内联函数默认在用的地方已经展开了,不需要产生。所以只有声明的话,在声明的地方已经展开了,这会导致在调用的时候没法展开。

五、总结

优点:

  • 函数使用时进行替换,效率高

缺点:

  • 如果函数的代码较长,使用内联将消耗过多内存
  • 如果函数体内有循环,那么执行函数代码时间比调用开销大

建议:

  • 建议 inline 函数的定义放在头文件中
  • 经常使用且代码短的函数,才进行内联
  • 函数体内的代码比较长时,不使用内联
  • 函数体内出现多重循环时,不使用内联

在这里插入图片描述

这篇关于C++内联函数:那时我还太年轻,并不知道使用inline带来的效率,早已在暗中标好了价格的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/672905

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象