C++深入分析内联函数的使用

 更新时间:2022年04月21日 15:30:20   作者:清风自在 流水潺潺  
为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数

一、常量与宏回顾

C++中的const常量可以替代宏常数定义,如︰

但是C++中是否有解决方替代宏代码片段呢?这里就要引入内联函数。

二、内联函数

  • C++中推荐使用内联函数替代宏代码片段
  • C++中使用 inline 关键字声明内联函数

内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求

  • C++编译器可以将一个函数进行内联编译
  • 被C++编译器内联编译的函数叫做内联函数
  • C++编译器直接将函数体插入函数调用的地方
  • 内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)

C++编译器不一定满足函数的内联请求

下面先看一段宏定义的代码:

#include <stdio.h>
#define FUNC(a, b) ((a) < (b) ? (a) : (b))
inline int func(int a, int b)
{
    return a < b ? a : b;
}
int main(int argc, char *argv[])
{
    int a = 1;
    int b = 3;
    int c = FUNC(++a, b);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);
    return 0;
}

下面为输出结果,c =FUNC(++a, b),等价于 c =((++a) < (b) ? (++a) : (b)),先执行(++a) < (b),得到 a =,2,b = 3,由于 ++a 比 b 小,所以输出 ++a,这个时候 a = 3,所以 c 也等于 3。

如果使用内联函数,

#include <stdio.h>
#define FUNC(a, b) ((a) < (b) ? (a) : (b))
inline int func(int a, int b)
{
    return a < b ? a : b;
}
int main(int argc, char *argv[])
{
    int a = 1;
    int b = 3;
    int c = func(++a, b);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);
    return 0;
}

输出结果如下:

下面在 VS2012 中看一下反汇编的代码,看一看内联有没有成功。可以看到 func 函数被调用,而不是直接扩展到被调用的地方,内联没有成功。inline 这个关键字仅仅是请求将函数内联,但是不一定会成功。

为了让编译器允许对内联的请求,可以对编译器进行一些配置,如下图

配置好以后,在 int c = func(++a, b); 前面打个断点,开始跑代码,但是我跑的时候报错了。

这个时候,进行下面配置,那个错误就解决了。

这个时候在进行反汇编,如下图所示,可以看到调用函数的汇编代码没有了,表示内联成功了。

  • 内联函数具有普通函数的特征(参数检查,返回类型等)
  • 函数的内联请求可能被编译器拒绝
  • 函数被内联编译后,函数体直接扩展到调用的地方

宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程,因此可能出现副作用。

现代C++编译器能够进行编译优化,一些函数即使没有inline声明,也可能被内联编译

一些现代C++编译器提供了扩展语法,能够对函数进行强制内联,如︰

  • g++ : _attribute__((always_inline)) 属性
  • MSVC : _forceinline

三、内联函数使用注意事项

C++中 inline 内联编译的限制:

  • 不能存在任何形式的循环语句
  • 不能存在过多的条件判断语句
  • 函数体不能过于庞大
  • 不能对函数进行取址操作
  • 不能对函数进行取址操作

四、小结

  • C++中可以通过 inline 声明内联函数
  • 编译器直接将内联函数体扩展到函数调用的地方
  • inline 只是一种请求,编译器不一定允许这种请求
  • 内联函数省去了函数调用时压栈,跳转和返回的开销

到此这篇关于C++深入分析内联函数的使用的文章就介绍到这了,更多相关C++内联函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Qt实现TCP网络编程

    Qt实现TCP网络编程

    这篇文章主要为大家详细介绍了Qt实现TCP网络编程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C++实现LeetCode(29.两数相除)

    C++实现LeetCode(29.两数相除)

    这篇文章主要介绍了C++实现LeetCode(29.两数相除),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言分支和循环详解

    C语言分支和循环详解

    C语言是一门结构化的程序设计语言,当C语言用来描述生活中的事物时,会用到三种结构:顺序结构(不去赘述),选择结构(对应分支语句),循环结构(对应循环语句),分支语句:分支语句分为两种,一种是if语句,一种是switch语句
    2021-10-10
  • 解析C语言中位字段内存分配的问题

    解析C语言中位字段内存分配的问题

    本篇文章是对C语言中位字段内存分配的问题进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ 中 vector 的常用操作方法汇总

    C++ 中 vector 的常用操作方法汇总

    在C++的STL中,vector是一个动态数组,可以在运行时调整大小,本文介绍了vector的初始化、元素访问、修改、迭代器操作、容量管理以及性能优化技巧,通过这些操作,可以有效地使用vector管理数据,本文介绍C++  vector 操作,感兴趣的朋友一起看看吧
    2024-10-10
  • C语言中条件编译详解

    C语言中条件编译详解

    预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。条件编译有三种形式,下面分别介绍。
    2017-05-05
  • C#使用反射加载多个程序集的实现方法

    C#使用反射加载多个程序集的实现方法

    下面小编就为大家带来一篇C#使用反射加载多个程序集的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • c/c++那些你一定会出错的数组笔试题汇总

    c/c++那些你一定会出错的数组笔试题汇总

    这篇文章主要给大家汇总介绍了关于c/c++那些你一定会出错的数组笔试题,除了基本数据类型之外,其余的都作为类对象,包括数组,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • Matlab实现绘制立体玫瑰花的示例代码

    Matlab实现绘制立体玫瑰花的示例代码

    这篇文章主要介绍了如何利用Matlab实现绘制更立体的玫瑰花,文中的示例代码讲解详细,对我们学习Matlab有一定的帮助,需要的可以参考一下
    2023-02-02
  • C语言动态内存泄露常见问题内存分配改进方法详解

    C语言动态内存泄露常见问题内存分配改进方法详解

    今天遇见了一道有意思的内存泄露题目,特地分享给大家,相信屏幕前的你学习完一定有所收获,预祝读者学习愉快,多多进步早日升职加薪
    2021-10-10

最新评论