21天学会C++:Day6----内联函数

news2024/11/27 18:24:02

· CSDN的uu们,大家好。这里是C++入门的第六讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题

目录

 1. 知识引入

2. 知识点讲解

2.1 内联函数的使用

2.2 内联函数的特性 

2.2 内联函数的注意点

3. 面试题


 1. 知识引入

在学C语言的宏时,我们了解了宏函数的概念与用法。我们也知道宏函数有一些易错点,稍不注意就可能出错!你若过不相信的话,就别看下面的代码自己写一个 a + b 的宏函数。

#define ADD(a, b) ((a) + (b))

int main()
{
	cout << ADD(10, 20) << endl;
	return 0;
}

不知道UU们写对了吗?为什么说宏函数容易写错呢?我们知道红的特性就是替换,这种特性会使我们遇到一些难以避免的错误,我们来看看这些常见的错误:

不加外面的括号替换之后由于运算符的优先级问题,导致结果出错!

#define ADD(a, b) (a) + (b)

int main()
{
	cout << ADD(10, 20) * 2 << endl; //使用宏函数
	cout << (10) + (20) * 2 << endl; //宏函数替换之后
	return 0;
}

 下面的代码同样也存由于运算符的优先级产生的问题:加法的优先级更高,导致结果出错。

#define ADD(a, b) (a + b)

int main()
{
	int a = 1, b = 2;
	cout << ADD(a | b, a & b) << endl; //使用宏函数
	cout << (a | b + a & b) << endl; //宏函数替换之后
	return 0;
}

那你可能会说了:那我每次都想正确的写法那样,多加几个括号不就能避免这种错误啦!很遗憾因为宏的替换特性,有些错误难以避免,观察如下代码:

我们尝试利用一个宏函数求解 b 的平方,但是我们用 ++b 来使用该函数,替换之后 ++b 会被执行两次,显然最终的结果并不是我们想要的。

#define Square(a) ((a) * (a))

int main()
{
	int b = 2;
	cout << Square(++b) << endl; //使用宏函数
	cout << ((++b) * (++b)) << endl; //宏函数替换之后
	return 0;
}

 但是呢宏还是有优点的,下面我们就来看看宏的优缺点:

优点:宏函数不需要建立函数栈帧,可以提高调用的效率。

缺点:不方便进行调试。(预处理阶段会进行宏的替换)

           代码可读性差,可维护性差,容易误用。

           没有类型安全的检查。(宏仅仅是替换嘛)。

C++ 是既想要宏的优点,又不想要宏的缺点。因此C++引入了内联函数。

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

2. 知识点讲解

2.1 内联函数的使用

用法很简单,我们只要在一个函数返回值的前面加上 inline 关键字即可。像这样:

inline int Add(int x, int y)
{
	return x + y;
}


int main()
{
	cout << Add(2, 3) << endl;
	return 0;
}

2.2 内联函数的特性 

再来看看内联函数的概念吧:

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

这里的在调用内联函数的地方展开,指的是:内联函数经过编译之后,会直接在调用处转化成汇编代码,而不是通过 call 指令,跳转到函数的实际地址处进行函数汇编代码的执行。 

在VS2019的debug模式下,默认是不会对程序进行优化的,我们看不到内联函数的展开,但是在release模式下又不支持调试,因此我们需要进行相关的设置才能看到内联函数的展开。

在项目---->属性中更改下面的设置即可 

我们通过调试下面的代码,然后查看汇编代码之后发现 Add 函数的调用并不是 call 函数地址而是直接在函数调用的地方展开,变成了汇编代码。

1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建
议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不
是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

2.2 内联函数的注意点

通过上面的调试过程我们直到内联函数是直接在调用处展开的,因此内联函数并没有函数地址。也就是说,内联函数不会出现在符号表中,也就意味着内联函数不可使用函数定义与函数声明分开的写法。

 为什么会报错呢?UU们不妨结合编译,链接的相关知识想一想。 

Add函数是内联函数,在调用Add函数的地方,编译器会在调用的地方展开。但是在调用Add函数的源文件中,只有Add函数的声明。 编译器无法做到在调用的地方展开,于是编译器会尝试通过 call 指令去调用函数,但是内联函数不会在符号表中出现,就会找不到函数的地址。因此会出现链接错误。

因此我们得出一个重要的结论:内联函数的声明与定义不可分离。

那应该怎么解决这个问题呢?很简单,直接在头文件里面写内联函数的定义即可。

3. 面试题

 宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?
1. 常量定义 换用const enum
2. 短小函数定义 换用内联函数

 

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

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

相关文章

强大Excel 插件 Zbrainsoft Dose for Excel 3.6.2 Crack

强大的 Excel 插件 Zbrainsoft Dose for Excel 3.6.2 如果您厌倦了在Excel中消除重复的行&#xff0c;比较工作表或执行困难的活动&#xff0c;那么Dose for Excel是您需要的强大便捷解决方案&#xff0c;只需单击几下即可将所有这些复杂的杂务简化。它具有 100 多个强大的新功…

pytorch实战 -- 自动微分

autograd——自动求导系统 import torch torch.manual_seed(7) <torch._C.Generator at 0x7f3c1f9e0490> torch.autograd.backward(tensors, grad_tensorsNone, retain_graphNone, create_graphFalse) 功能&#xff1a;自动求取梯度 tensors&#xff1a;用于求导的张量&…

axios-CancelToken方法取消请求-控制多次同样api调用取消上一次接口调用

前言 开发当中看到了axios取消方法&#xff0c;经过查阅&#xff0c;axios这个包是提供了取消请求的方法的。 移动端当是tab栏类的页面&#xff0c;或者是下拉刷新和上拉加载是一个接口是&#xff0c;会出现20条情况&#xff08;接口调用2次&#xff09;。 pc端同一个按钮&am…

【欢迎您,xxx--JavaScript】

login.html <body><form action"index.html">用户名&#xff1a;<input type"text" name"usname"><input type"submit" value"登录"></form> </body> index.html <body><di…

BERT在GLUE数据集构建任务

0 Introduction 谷歌开源的BERT项目在Github上&#xff0c;视频讲解可以参考B站上的一个视频 1 GLUE部分基准数据集介绍 GLUE数据集官网GLUE数据集下载&#xff0c;建议下载运行这个download_glue_data.py文件进行数据集的下载&#xff0c;如果链接无法打开&#xff0c;运行…

七、Gitee码云的注册及使用(二)

1、创建远程仓库 (1)登录Gitee.com&#xff0c;点击右上角 号&#xff0c;再点击新建仓库。 (2)填写仓库名称&#xff0c;路径&#xff0c;仓库介绍 (3)选择是否开源 (4)初始化仓库 开源许可证&#xff1a;主要包括开源是否可以随意转载&#xff0c;开源但不能商业使用&…

yolov8改进大作战,开箱即用,提供yolov8魔术师专栏代码

1.yolov8魔术师专栏介绍 开箱即用&#xff1a;提供 yolov8魔术师专栏 代码&#xff0c;方便直接使用&#xff0c;无需自己重新添加引起的一些bug问题&#xff1a; https://blog.csdn.net/m0_63774211/category_12289773.html?spm1001.2014.3001.5482 专栏内容如下&#xff…

【深入浅出Spring Security(五)】自定义过滤器进行前后端登录认证

自定义过滤器 一、自定义过滤器自定义登录认证过滤器自定义 LoginFilter配置 LoginFilter测试 二、总结 一、自定义过滤器 在【深入浅出Spring Security&#xff08;二&#xff09;】Spring Security的实现原理 中小编阐述了默认加载的过滤器&#xff0c;里面有些过滤器有时并…

OpenGL实现第一个窗口-三角形

1.简介 此代码是基于QtOpenGL实现的&#xff0c;但是大部分的代码是OpenGL&#xff0c;Qt封装了一些类&#xff0c;方便使用。 2.准备工作 QOpenGLWidget提供了三个便捷的虚函数&#xff0c;可以重写&#xff0c;用来重写实现典型的OpenGL任务。不需要GLFW。 paintGL&#…

【C语言】Visual Studio社区版安装配置环境(保姆级图文)

目录 1. 官网下载社区版2. 选择安装项目2.1 点击使用C的桌面开发2.2 语言包选择简体中文2.3 设置安装位置 3. 创建新项目3.1 点击创建新项目3.2 点击空项目&#xff0c;下一步3.3 设置项目名称路径3.4 创建项目 4. 测试例程总结 欢迎关注 『C语言』 系列&#xff0c;持续更新中…

代码随想录 二叉树 Java (一)

文章目录 &#xff08;简单&#xff09;144. 二叉树的前序遍历&#xff08;简单&#xff09;94. 二叉树的中序遍历&#xff08;简单&#xff09;145. 二叉树的后序遍历二叉树的统一遍历方法&#xff08;参考代码随想录&#xff09;&#xff08;中等&#xff09;102. 二叉树的层…

横岗茂盛村旧改,已立项,一期已拆平。

项目位于龙岗区横岗街道红棉路与茂盛路交汇处&#xff0c;距离轨道3号线横岗站约700米。 茂盛片区城市更新单元规划&#xff08;草案&#xff09;已经在近日公示&#xff0c;该旧改被纳入《2012年深圳市城市更新单元计划第五批计划》&#xff0c;2019年曾被暂停&#xff0c;20…

Redis实战14-分布式锁基本原理和不同实现方式对比

在上一篇文章中&#xff0c;我们知道了&#xff0c;当在集群环境下&#xff0c;synchronized关键字实现的JVM级别锁会失效的。那么怎么解决这个问题呢&#xff1f;我们可以使用分布式锁来解决。本文咱们就来介绍分布式锁基本原理以及不同实现方式对比。 我们先来回顾&#xff…

【深度学习】混合精度训练与显存分析

混合精度训练与显存分析 ​ 关于参数精度的介绍可以见文章https://zhuanlan.zhihu.com/p/604338403 相关博客 【深度学习】混合精度训练与显存分析 【深度学习】【分布式训练】Collective通信操作及Pytorch示例 【自然语言处理】【大模型】大语言模型BLOOM推理工具测试 【自然语…

(论文阅读)Chain-of-Thought Prompting Elicits Reasoningin Large Language Models

论文地址 https://openreview.net/pdf?id_VjQlMeSB_J 摘要 我们探索如何生成一个思维链——一系列中间推理步骤——如何显著提高大型语言模型执行复杂推理的能力。 特别是&#xff0c;我们展示了这种推理能力如何通过一种称为思维链提示的简单方法自然地出现在足够大的语言模…

2023 更新版:苏生不惑开发过的那些原创工具和脚本

苏生不惑第431 篇原创文章&#xff0c;将本公众号设为星标&#xff0c;第一时间看最新文章。 4年来苏生不惑这个公众号已经写了400多篇原创文章&#xff0c;去年分享过文章更新版&#xff1a;整理下苏生不惑开发过的那些工具和脚本 &#xff0c;今年再更新下我开发过的原创工具…

【Python开发】FastAPI 07:Depends 依赖注入

在 FastAPI 中&#xff0c;Depends 是一个依赖注入系统&#xff0c;用于注入应用程序中所需的依赖项&#xff0c;通过 Depends&#xff0c;我们可以轻松地将依赖项注入到 FastAPI 路由函数中。简单来说&#xff0c;Depends 依赖注入的目的就是将代码重复最小&#xff01; 目录 …

Vue学习3

文章目录 Vuex工作原理配置环境各种函数mapState对象写法数组写法 MapGetterMapMutations对象写法数组写法 Mapaction总结 模块化模块化1总结 Vuex 工作原理 那三个要通过store管理 配置环境 使用import时&#xff0c;回先执行Import中的代码,在后面的也会提前。 index.js…

Vscode利用ssh登录ubuntu开发环境下,代码不能跳转问题解决

0 开发环境 环境&#xff1a;VScode remote ssh 虚拟机Ubuntu22.04 1 问题记录 在win环境下&#xff0c;Vscode可以实现代码跳转。但是&#xff0c;在利用VScode的ssh登录Ubuntu下&#xff0c;代码不能进行跳转。 网上看到很多帖子&#xff0c;有的更改settings.json&…

【Ubuntu】保姆级图文介绍双系统win10卸载Ubuntu16.04

文章目录 删除Ubuntu分区数据删除Ubuntu启动项 这段时间想将前几年安装的Ubuntu16.04版本升级到Ubuntu20.04。 折腾了一番&#xff0c;升级失败了。想着还不如卸载了重新安装Ubuntu20.04。 由于Ubuntu16.04在升级过程中出现了一些问题&#xff0c;导致进不去Ubuntu系统。因此只…