【C++】内联函数----inline函数的详细使用教程

news2025/1/22 12:18:34

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟
👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏

文章目录

  • 前言
  • 概念:
    • 出现动机:
      • C语言的解决方案:宏函数
      • 新方案:C++方案---内联函数
          • 总结:
          • 内联函数替代宏函数
  • 特性:
    • 以空间换时间
    • 内联函数只是一个请求:
      • 适用范围
      • 再举个栗子:代码膨胀
    • inline不建议声明和定义分离:
      • 举个栗子:
        • 正常情况(预处理-编译-链接)
          • 预处理:
          • 编译:
          • 链接:
        • 内联情况:
          • 预处理:
          • 编译:
          • 链接:
    • 建议:
    • 总结:
  • 注意事项:
    • 宏的优缺点?
      • 优点:
      • 缺点:
    • 长不用,短用内联函数。
  • 最后


前言

今天我们来学习C++中的一个比较重要的关键字–inline函数(内联函数),码字不易,希望多多支持!!!
在这里插入图片描述

——————————————————————————————

概念:

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

出现动机:

减少函数栈帧的开辟和销毁,如当频繁调用一个函数的时候(比如快排算法中函数多次被调用),此时消耗栈帧的比较大(不断地调用栈帧销毁栈帧)。
因此要将函数栈帧的优化掉

C语言的解决方案:宏函数

对于C语言中,可以使用宏函数。
使用宏函数为什么没有函数栈帧的消耗???
因为在预处理阶段就被替换了----优化了,没有了函数的栈帧的消耗了

新方案:C++方案—内联函数

有些人可能会比较疑惑:C语言中已经有方案了,为什么C++为什么还要再设计一个关建字方案:
因为宏函数有很多不方便的地方:

  1. 不可以调试
  2. 没有类型安全检查
  3. 容易写错
    比如你可以写一个ADD宏函数来验证:
#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)
#define ADD(x, y) ((x) + (y));

这五种写法都是很有可能是你写出来的(最后一个是对的,其余全是错的)
这几个宏定义的写法都是错误的,具体原因如下:

  1. #define ADD(int x, int y) {return x + y;}

该写法定义了一个带有参数列表的宏,但是参数列表应该在括号内,而不是放在宏名后面即ADD(int x, int y),正确的定义应该是:

#define ADD(x, y) {return x + y;}
  1. #define ADD(x, y) x + y

该写法没有使用括号把宏展开式中的参数括起来,可能会导致运算顺序出现问题。比如:

int result = 2 * ADD(3, 4);

在展开后就变成了 int result = 2 * 3 + 4; 发生了预期外的错误。 正确写法应该是:

#define ADD(x, y) ((x) + (y))
  1. #define ADD(x, y) (x + y)

该写法同样没有使用括号将宏展开式中的参数括起来,同样可能导致运算次序出现问题。比如:

int result = 2 * ADD(3, 4);

等价于 int result = 2 * (3 + 4); 发生了预期外的错误。正确写法应该是:

#define ADD(x, y) ((x) + (y))
  1. #define ADD(x, y) (x) + (y)

该写法看似使用括号将宏展开式中的参数括起来,但是由于缺少返回值表达式,比如return关键字,可能导致编译错误,语法上存在问题。 正确写法应该是:

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

总而言之,在定义宏时,需要注意参数列表和展开式的正确书写,以及是否需要

总结:

在这里插入图片描述
因此宏函数极易出现错误。
这个知识点容易出错,但是面试的时候易被问到。

内联函数替代宏函数

在函数返回值前加一个inline即可, 那么函数就会在调用位置直接展开:
在这里插入图片描述

可以通过vs2013编译器上通过反汇编进行查看这个:
查看方式:

  1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
  2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化,以下给出vs2013的设置方式)debug模式下不展开是因为为了支持调试!!!
    在这里插入图片描述
    在这里插入图片描述

特性:

以空间换时间

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

内联函数只是一个请求:

在这里插入图片描述

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

适用范围

经验条款:C++中用Inline,const,enum来替换宏
在这里插入图片描述
适用范围:频繁调用小函数的时候:
在这里插入图片描述
但是内联函数是一个请求,不一定展开,当你频繁调用大函数的时候(干一些坏事情)编译器不会展开。
编译器有自己的规则,不喜欢你多管,hh
在这里插入图片描述
在这里插入图片描述

再举个栗子:代码膨胀

在这里插入图片描述
指令影响的是什么-----安装包
在这里插入图片描述
安装包大了–必然不好

inline不建议声明和定义分离:

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

举个栗子:

正常情况(预处理-编译-链接)

代码

预处理:

首先编译器会对这个代码进行预处理,变成这个样子:即将所应用的头文件的内容放到文件内----
在这里插入图片描述

编译:

接下来进行代码的编译:
在这里插入图片描述
编译的时候将代码转换为汇编指令:此时我们可以看到Test.cpp文件中call的func函数的函数地址是未知的,正常情况是会在链接的时候在符号表中查找并将函数地址填入进行调用。

链接:

在这里插入图片描述
上面是正常的情况,下面说一下,当Inline函数调用和声明分离的时候:

内联情况:

预处理:

在这里插入图片描述

编译:

在这里插入图片描述
stack.cpp文件内不会生成指令,因为没有调用

链接:

在这里插入图片描述

建议:

直接在.h文件内定义就行了

总结:

在这里插入图片描述
只要是内联函数,函数定义与声明分离的时候,内联函数的函数地址不会进符号表,要不然还要判断编译器是否应用内联函数,这样太复杂了!!!

在这里插入图片描述
在这里插入图片描述

注意事项:

宏的优缺点?

优点:

1.增强代码的复用性。
2.提高性能。

缺点:

1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?

  1. 常量定义 换用const enum
  2. 短小函数定义 换用内联函数

长不用,短用内联函数。


最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/522227.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享一个一键换肤按钮(超酷)

先上效果图&#xff1a; 效果图中转换为黑夜会有一个宇航员小猴子飞上来&#xff0c;途中没有截到。。。。 废话不多说&#xff0c;上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title…

通过VS开发人员命令提示符(developer command prompt)查看类

1.首先打开开始菜单栏&#xff0c;找到相应的VS版本。这里以VS2022为例 2.找到developer command prompt选项&#xff0c;点击进入 3.进入控制台&#xff0c;进入源文件所在的盘符&#xff08;这里以D盘为例&#xff0c;如果是默认C盘可以不用改&#xff09; 4.输入cd 文件地址…

printBanner

主类 package com.example.demo;import com.application.Application;public class Demo {public static void main(String[] args) {Application application new Application("application.properties");application.run();}}创建对象&#xff0c;需要的参数&…

第十三届蓝桥杯青少组省赛Python真题,包含答案

目录 一、选择题 二、编程题 第十三届蓝桥杯青少组省赛Python真题,包含答案 一、选择题 第 1 题 单选题 下列关于函数的说法正确的是 () 。 答案&#xff1a;C 第 2 题 单选题 十进制数55转换成十六进制是 () 。 答案&#xff1a;C 第 3题 单选题 下列方法中&#xff0c;哪…

Sysfs简介

Sysfs学习记录 主要参考文献&#xff1a;https://xuesong.blog.csdn.net/article/details/109522945 Sysfs(System File System)是一种虚拟文件系统&#xff0c;它提供了一种在Linux和Unix系统中管理设备和内核参数的机制。Sysfs基于内核&#xff0c;将底层硬件信息和内核参数…

WPF:WPF原生布局说明

前言 WPF在国内讨论度很小&#xff0c;我在这里记录一下WPF简单的原生控件是如何使用的&#xff0c;顺便回忆一下WPF的基础知识&#xff0c;有些忘记的比较厉害了 WPF简介 WPF是微软推出的桌面UI软件&#xff0c;是我觉得最早实现MVVM&#xff08;数据驱动事务&#xff09;&…

三、H3C-NE实验-配置管理实验

实验拓扑图&#xff1a; 实验描述&#xff1a; 1&#xff09;把路由器R配置为FTP服务器&#xff1b; 2&#xff09;在R上save配置文件后&#xff0c;主机登录FTP&#xff0c;把R的配置文件copy备份&#xff1b; 3&#xff09;删掉R的配置文件后&#xff0c;利用主机恢复R的配…

42个网工高效率工具,我只告诉你(一)

晚上好&#xff0c;我是老杨。 不知道上一篇书单总结&#xff0c;你是否觉得干货 今天更新第四篇&#xff0c;也是最后一篇总结——2022年全年&#xff0c;我安利给你的网工好用工具&#xff0c;整整42个。 它是什么&#xff0c;为什么好用&#xff0c;哪里下载&#xff0c;…

【Linux】进程信号详解(二)

文章目录 前言一、信号阻塞1.信号其他相关常见概念信号递达&#xff1a;信号未决&#xff1a;信号阻塞&#xff1a;信号阻塞vs信号递达的忽略动作 2. 在内核中的表示3. sigset_t4. 信号集操作函数5.sigprocmask函数6.sigpending 二、深入理解捕捉信号1. 虚拟地址空间2.用户态和…

mybatis是如何集成到spring的?

文章目录 1 前言1.1 集成spring前使用mybatis的方式1.2 集成mybatis到spring的关键步骤 2 SqlSessionFactoryBean对象分析2.1 buildSqlSessionFactory做了什么事情&#xff1f;2.2 为什么是SqlSessionFactoryBean却可以使用SqlSessionFactory&#xff1f; 3 验证demo4 举一反三…

【Python 爬虫之BeautifulSoup】零基础也能轻松掌握的学习路线与参考资料

BeautifulSoup是一种Python库&#xff0c;用于解析HTML和XML文档&#xff0c;并从中提取数据。它提供了Pythonic的解决方案来处理非结构化数据&#xff0c;因此可以轻松地从网页上提取数据。 使用BeautifulSoup编写爬虫&#xff0c;你可以自动化许多任务&#xff0c;比如数据抓…

实验三 Spark SQL基础编程

实验三 Spark SQL基础编程 1.实验目的 1. 掌握 Spark SQL 的基本编程方法&#xff1b; 2. 熟悉 RDD 到 DataFrame 的转化方法&#xff1b; 3. 熟悉利用 Spark SQL 管理来自不同数据源的数据。 2.实验内容 1&#xff0e;Spark SQL 基本操作 将下列 JSON 格式数据复制到 Li…

CF1245D Shichikuji and Power Grid 题解

CF1245D Shichikuji and Power Grid 题解 题目链接字面描述题面翻译样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 思路点拨代码实现 题目 链接 https://www.luogu.com.cn/problem/CF1245D 字面描述 题面翻译 已知一个平面上有 n n n 个城市&#x…

计网笔记 数据链路层 (1-2) 封装成帧、差错控制、流量控制与可靠传输、停止等待协议、后退N帧协议(GBN)、选择重传协议(SR)

文章目录 前言在这里插入图片描述 零、数据链路层基本概念一、功能0、数据链路层功能概述1、封装成帧和透明传输1.1封装成帧1.2 透明传输1.3组帧方法 2、数据链路层的差错控制2.0差错从何而来2.1位错&#xff08;比特错&#xff0c;1变成0&#xff0c;0变成1&#xff09;2.2帧错…

干货 | ChatGPT使用指南,让你轻松上车AI世界!

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 聊天机器人&#xff08;Chatbot&#xff09;是一种人工智能应用&#xff0c;可以模拟人类对话行为&#xff0c;以自然语言进行交互。 在过去的几年里&#xff0c;随着自然语言处理技术和深…

Springboot +Flowable,定时器的简单使用

一.流程定义定时激活 之前介绍流程定义的时候&#xff0c;流程都是定义好之后立马就激活了&#xff0c;其实在流程定义的这个过程中&#xff0c;我们还可以设置一个激活时间&#xff0c;也就是流程定义好之后&#xff0c;并不会立马激活&#xff08;不激活就不能据此流程定义创…

操作系统作业 第37-40章

第四次作业 第37章 本章作业需要使用提供的disk.py程序。该程序可以模拟磁盘的工作。在默认情况下&#xff0c;磁盘调度方法为FIFO。对于时间的计算&#xff0c;假设旋转一度为1个时间单位&#xff0c;旋转完整一圈需要360个时间单位&#xff0c;而一个磁道上默认有12个扇区&…

实验二 RDD基础编程

实验二 RDD基础编程 前提是配置好大数据环节。 hadoop&#xff0c;spark&#xff0c;scala等必须的软件 以及下载pyshark 1.实验目的 1. 掌握 RDD 基本操作&#xff1b; 2. 熟悉使用 RDD 编程解决实际具体问题的方法&#xff1b; 2.实验内容 本人仅提供测试代码&#xff01;…

策划专业技能提升攻略,让你在职场中脱颖而出

作为一个10多年的老策划&#xff0c;刚入行的时候也走过很多弯路&#xff0c;后来加入到一家在国内比较知名的策划公司&#xff08;老板也是当年的十大知名策划人&#xff09;才真正让我实现水平的跃升。 当时公司经常有内训&#xff0c;新人的第一课就是策划人应该如何快速入…

FreeRTOS-事件组详解

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转FreeRTOS &#x1f4ac;保持…