• C++函数内联详解


    本文旨在讲解C++中的函数内联相关知识,读完这篇文章,希望读者们会对函数内联有更深一步的认识!


    内联函数的定义

    计算机科学中, 内联函数 (有时称作 在线函数 或 编译时期展开函数 )是一种编程语言结构,用来建议 编译器 对一些特殊 函数 进行内联扩展(有时称作在线扩展 ;也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方( 上下文 ),从而节省了每次调用函数带来的额外时间开支)


    C++引进内联函数的原因

    C++语言支持内联函数,其目的是为了提高函数的执行效率(速度)。


    宏定义的缺陷

    在C程序中,常常使用宏定义来提高代码执行效率宏定义本身不是一种函数,它只是一种简单的替代,其省去了参数压栈,生成汇编语言的CALL调用,返回参数,执行return等过程,从而提高了速度使用宏定义的最大缺点是容易出错,预处理器在拷贝宏代码时常常会产生意想不到的边界效应!通过阅读下面代码可以发现宏定义的一些缺点!

    1.代码容易出错

    1. #define Add(x,y) x+y
    2. int main()
    3. {
    4. int result = 3 * Add(1, 2);
    5. cout << result << endl; //结果输入5
    6. }

    对于上述代码,初学者很容易将宏函数代码写错,没有加上括号,从而导致结果与自己预期的结果有出入!

    2.宏定义不可调试

    宏的另一个缺点就是不可调试,但是内联函数可以调试,内联函数不是像宏一样进行代码的展开么?怎么能够调试呢?其实内联函数的“可调试”不是说它展开后还可以调试,而是在程序的调试版本(Debug)版本里它根本没有真正的内联,编译器像普通函数那样为它生成含有调试信息的可执行代码,在程序的发行(Release)版本里,编译器才会实现真正的内联,所以我们可以通过release版本来观察其内联的实现过程!

    判断函数成为内联函数

    可以通过简单的调试,将代码转化为汇编代码,然后通过观察底层的实现,因为调用函数栈帧会使用Call指令,这是一种简单的观察方法!


    内联函数的编程风格

    注:内联函数的定义和声明不能分离!

    关键字Inline必须与函数定义体放在一起才能使函数实现真正的内联,仅把inline放在函数声明的前面不起任何作用!

    例如如下代码!

    1. 如下风格的Add函数不能成为内联函数!
    2. inline void Add(int x,int y); //inline仅与函数放在声明放在一起
    3. void Add(int x,int y)
    4. {
    5. ********
    6. }
    7. 如下风格的Add函数可以成为内联函数!
    8. void Add(int x,int y);
    9. inline void Add(int x,int y) //inline与函数定义体放在一起!
    10. {
    11. ********
    12. }

    上述不能成为内联函数的情况编译器会报出如下错误!错误如下:

    编译器不能链接Add函数,这是为什么呢?因为定义时把Add函数定义为内联类型,其作用只是单纯的展开函数,其不会在符号表调用相关字符,地址等,所以当引用Add函数时,虽然编译器认识这个函数,但是它不知道下一步该干什么(如何链接到Add函数)!

    所以说,inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”,一般情况下,用户可以阅读函数声明的声明,但看不见函数的定义,尽管大多数教科书中在内联函数的声明和定义都加上了inline关键字,但是根据C++程序设计风格,inline不应出现在函数的声明中,因为用户没有必要知道函数是否需要内联!


    内联函数的特性

    1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。

    2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。


    慎用内联函数

    内联能提高函数的执行效率,为什么不把所有的函数都定义为内联函数呢?

    如果所有的函数都是内联函数,还用得着“内联”这个关键字么?

    内联并不是万能的!它以空间换时间为代价,仅仅省去了函数调用的开销,从而提高了程序的执行效率,注意:这里的“函数的调用开销”并不包括执行函数体所需要的开销,而是仅指参数压栈,跳转,退栈和返回操作,如果执行函数体内的代码时间比调用函数开销要大的多,那么内联的效率收入会很小,另一方面,每一处内联函数的调用都需要拷贝代码,使得程序的总代码量增大,消耗更多的内存空间!

    以下情况不宜使用内联:

    1.函数体内的代码较长,使用内联会使执行代码膨胀!

    2.函数体内存在过多的循环或控制结构,那么执行函数体内的代码的时间会比函数调用开销大的多,因此内联的意义并不大!


    至此,有关内联函数的介绍完毕,一些专业术语查自(高质量程序设计指南C/C++),希望读完这篇文章,能使读者对内联函数有更深一步的认识!

  • 相关阅读:
    UML——类图详解
    Python自动化测试框架pytest的详解安装与运行
    JVM 系列(6) —— JVM 类加载机制
    【毕业设计】基于STM32的自动加油站加油系统 -物联网 单片机 嵌入式
    【猫meme】轻松C语言-2.C语⾔数据类型和变量
    leetcode笔记(自用)
    一款构建Python命令行应用的开源库
    vue2中,使用sortablejs组件和vuedraggable实现拖拽排序功能
    k8s 资源管理
    Docker镜像原理
  • 原文地址:https://blog.csdn.net/weixin_71276184/article/details/132782778