深入理解C++内联函数

目录
  • 内联函数的概念
    • 内联函数和宏
    • 内联函数的特性
  • 总结

内联函数的概念

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

举个例子:

在C++中我们通常定义以下函数来求两个整数的最大值:

代码如下:

int max(int a, int b)
{
 return a > b ? a : b;
}

为这么一个小的操作定义一个函数的好处有:

  • 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多
  • 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多
  • 使用函数可以确保统一的行为,每个测试都保证以相同的方式实现
  • 函数可以重用,不必为其他应用程序重写代码

虽然有这么多好处,但是写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作:

- 程序需要存储当前地址,以便调用结束后返回继续执行
- 程序将传入函数的参数压栈
- 程序跳到跳到标记函数起点的内存单元,执行函数代码
- 函数调用结束后,将栈清空,返回到之前存储的地址继续执行

C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开,相当于直接copy一份函数体内代码,在执行到的时候直接按照代码顺序执行,省去了许多函数调用过程,节省了时间。

假设我们将 max 定义为内联函数:

代码如下:

inline int max(int a, int b)
{
 return a > b ? a : b;
}
则调用: cout<<max(a, b)<<endl;

在编译时展开为: cout<<(a > b ? a : b)<<endl;

从而消除了把 max写成函数的额外执行开销

是不是觉得这和有些像?那为什么不直接用宏?还要整个内联函数

内联函数和宏

首先,宏能够表达的意思有限,通常是一行的表达式。其次,用宏的安全性不高,容易出错。

假设定义宏如下:

#define MAX(a,b)  a>b?:a:b

那么语句

res = MAX(i,j)+2;

会被预处理器扩展为

res = i > j? i:j+2;

由于+的优先级高于?,因此最终比较结果与我们期望不符。
那如果把宏修改为

#define MAX(a,b) (i &gt; j? i:j)

仍然存在问题,例如

res = MAX(i++,j)
res = (i++ < j? i++:j);  // i被+了两次

同时,宏无法调试,但内联函数可以。在程序的调试版本,内联函数并没有真正内联,就像普通函数一样实现调试,在程序的发行版本,编译器才会实现真正内联。

无论是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 条款,还是《高质量程序设计指南——C++/C语言》中的“用函数内联取代宏”,宏在C++中基本是被废了。

内联函数的特性

1、inline是一种以空间换时间的做法,省了去调用函数的额外开销。由于内联函数会在调用的位置展开,所以代码很长或者有递归的函数不适宜作为内联函数。频繁调用的小函数建议定义成内联函数。

2、inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有递归等,编译器优化时会忽略掉内联。

3、inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了链接就会找不到。

4、关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

5 .相比于宏,有类型检查,安全性更高,具有一般函数特性,可调试。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++实操之内联成员函数介绍

    目录 前言 什么是内联函数: 如何使一个函数成为内联: 为什么使用内联: 优点 : 缺点 : 关键点 : 总结 前言 在C语言中,我们使用了宏函数,这是编译器用来减少执行时间的一种优化技术.那么问题来了,在C++中,有什么更好的方法来解决这个问题呢?我们引入了内联函数,这是编译器用来减少执行时间的一种优化技术.我们将讨论内联函数的 "what, why, when & how". 什么是内联函数: 内联函数是C++的一个增强功能,可以减少程序的执行时间.函数可以通过指示编译器,

  • C++ 内联函数详解

    目录 一.C++ 内联函数 1.内联 2.语法 3.评价 总结 一.C++ 内联函数 1.内联 C 语言中有宏函数的概念.宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销.但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错. 2.语法 C++提供了 inline 关键字,实现了真正的内嵌. 宏函数 VS inline函数 #include <iostream> #include <string.h> using namespace std; //优点:

  • C++内联函数详情

    内联函数是C++当中为了提高程序运行效率的设计,老实讲我没有在其他语言当中看到类似的设计.它和常规函数之间的主要区别不在于编写的方式,而是在于C++编译器会将内联函数组合到程序当中执行. 要解释这个过程会稍稍有些复杂,我们需要从编译的过程说起.对于编译型语言而言,编译器做的事情是把人类写出来人能读懂的代码翻译成机器能够识别.执行的机器语言,一般是一串十六进制的指令.随后计算机逐步执行这些指令,完成我们想要的功能. 当我们调用函数时,其实本质上是指令跳转,先记录下当前运行的指令位置,跳转到函数所在

  • c++ 内联函数和普通函数的区别

    前言 内联函数是c++为了提高程序的运行速度做的改进,它与普通函数区别在于: 编译器如何将它们组合到程序中.所以我们需要深入到程序内部. 我们的最终的可执行程序由 一组机器指令组成.程序运行时,计算机逐步执行指令. Ⅰ.常规函数 常规函数调用时会使程序跳到另一个地址(函数的地址),并且在函数结束时返回. 执行函数调用指令,立即存储该指令的地址,并将函数参数保存到的堆栈. 跳到函数起点的内存单元,执行函数代码(将返回值保存到寄存器中. 跳回被保存指令的地址处. 这一过程和系统中的中断很类似.来回跳

  • C++ 内联函数inline案例详解

    使用函数能够避免将相同代码重写多次的麻烦,还能减少可执行程序的体积,但也会带来程序运行时间上的开销. 函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(该地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后才跳转到函数内部执行.这个过程是要耗费时间的. 另外,函数执行 return 语句返回时,需要从栈中回收形参和局部变量占用的存储空间,然后从栈中取出返回地址,再跳转到该地址继续执行,这个过程也要耗费时间. 总之,

  • 深入理解C++内联函数

    目录 内联函数的概念 内联函数和宏 内联函数的特性 总结 内联函数的概念 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数的使用可以提升程序的运行效率. 举个例子: 在C++中我们通常定义以下函数来求两个整数的最大值: 代码如下: int max(int a, int b) { return a > b ? a : b; } 为这么一个小的操作定义一个函数的好处有: 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它

  • 深入探讨:宏、内联函数与普通函数的区别

    内联函数的执行过程与带参数宏定义很相似,但参数的处理不同.带参数的宏定义并不对参数进行运算,而是直接替换:内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数.    内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定:而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患.    使用内联函数时,应注意以下问题:    1)内联函数的定

  • C++编程中队内联函数的理解和使用

    函数调用过程 c++经过编译生成可执行程序文件exe,存放在外存储器中.程序启动,系统从外存储器中将可执行文件装载到内存中,从入口地址(main函数起始处)开始执行.程序执行中遇到了对其他函数的调用,就暂停当前函数的执行,并保存下一条指令的地址作为从被调函数返回后继续执行的入口点,保存现场.然后转到被调函数的入口地址执行被调函数.遇到return语句或者被调函数结束后,恢复先前保存的现场,从先前保存的返回地址处继续执行主调函数的其余部分. 内联函数 函数调用需要进行现场保护,以便在函数调用之后继

  • Kotlin中关于内联函数的一些理解分享

    前言 看了很多博客,才明白了内联的含义,其实最根本的就是将写在别处的代码拷贝到你现在执行的方法中,相当于在一个方法中执行,java的方法执行是需要压栈出栈的对吧,如果是两三个方法那就是两三次的压栈出栈,为了节省这个操作,提高一定的效率,kotlin就出了这么个函数.但又想想,如果是个超级大的函数,考来考去的也是很麻烦啊,所以这东西需要自己权衡吧,遵守单一职责,降低代码圈发杂度才是根本. 内联函数的理解 inline函数(内联函数)从概念上讲是编译器使用函数实现的真实代码来替换每一次的函数调用,带

  • kotlin Standard中的内联函数示例详解

    let.with.run.apply.also.takeIf.takeUnless.repeat函数的使用 kotlin Standard.kt文件中,提供了一些内联函数,这些内联函数可以减少代码量,在使代码优美的同时,打打提高开发效率.它们分别为: run.with.let.also.apply let let函数的定义如下: public inline fun <T, R> T.let(block: (T) -> R): R = block(this) 默认当前这个对象作为闭包的it

  • C++入门(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for)

    一.C++关键字 C++总共有63个关键字,在入门阶段我们只是大致了解一下就可,在后续博客中会逐渐讲解 二.命名空间 相信学过C++的同学,一定都写过下面这个简单的程序 #include<iostream> using namespace std; int main() { cout<<"hello world"<<endl; return 0; } 我们先来看第二行代码,using namespace std , 这行代码是什么意思呢 ? 这里我们

  • C++ 引用与内联函数详情

    目录 引用初阶 什么是引用 为何要有引用 引用指向同一块空间 引用的特性 定义时必须初识化 一个变量可以多次引用 引用一旦引用了一个实例,不能在再引用其他的实例 引用进阶 常引用 权限 临时变量具有常属性 引用的场景 做参数 返回值 引用做返回值 引用不会开辟空间 引用和指针比较 内联函数 为何存在 内联函数 展开短小的函数 内联函数的特性 较大的函数编译器不会发生内联 声明定义一起 引用初阶 引用是C++的特性的之一,不过C++没有没有给引用特意出一个关键字,使用了操作符的重载.引用在C++中

  • C++深入探索内联函数inline与auto关键字的使用

    目录 1.内敛函数 1.1问题引入 1.2内联函数的概念 1.3内敛函数的特性 2.auto关键字 2.1 auto简介 2.2 auto的使用细则 2.3 auto不能推导的场景 2.4 auto与新式for循环使用 1.内敛函数 1.1问题引入 我们在使用C语言中我们都学过函数,我们知道函数在调用的过程中需要开辟栈帧.如果我们需要频繁的调用一个函数,假设我们调用10次Add()函数,那我们就需要建立10次栈帧.我们都知道在栈帧中要做很多事情,例如保存寄存器,压参数,压返回值等等,这个过程是很

  • C++类与对象深入之引用与内联函数与auto关键字及for循环详解

    目录 一:引用 1.1:概念 1.2:引用特性 1.3:常引用 1.4:使用场景 1.5:引用和指针的区别 二:内联函数 2.1:概念 2.2:特性 2.3:面试题 三:auto关键字 3.1:auto简介 3.2:auto使用细则 3.3:auto不能推导的场景 四:基于范围的for循环 4.1:范围for循环的语法 4.2:范围for循环的使用条件 一:引用 1.1:概念 引用不是定义一个新的变量,而是给已经存在的变量取一个别名.注意:编译器不会给引用变量开辟内存空间,他和他的引用变量共用同

随机推荐