返回值的理解

news2025/1/12 13:45:08

前言

我们写的函数是怎么返回的,该如何返回一个临时变量,临时变量不是出栈就销毁了吗,为什么可以传递给调用方?返回对象的大小对使用的方式有影响吗?本文将带你探究这些问题,阅读本文需要对函数栈帧有一定的理解,并了解基本的汇编指令。

文章汇编代码:采用 GCC 8.3.1,对 C 代码使用 -Og 优化级别生成的可执行程序,再用 objdump -d 反汇编的结果。

寄存器保存

如果返回的对象比较小,寄存器可以放得下,返回值将被放到 %rax 中。%rax 只能存放整数数据和指针,浮点数使用另外一组单独的寄存器。

返回寄存器

来看一段简单的代码:

// 一段简单让两数相乘的代码,写成这种形式,主要是尽量减少编译器优化
long mult2(long a, long b) {
    long t = a * b;
    return t;
}

void mult_store(long x, long y, long* dest) {
    long t = mult2(x, y);
    *dest = t;
}
00000000004004d2 <mult2>:
  # a in %rdi,b in %rsi
  4004d2:   mov    %rdi,%rax	# 把 a 移动到 %rax
  4004d5:   imul   %rsi,%rax	# 此时 %rax 保存的是参数 a,再将 %rsi 保存的参数 b 乘到 %rax
  4004d9:   retq				# 这时 %rax 保存的是 a * b

00000000004004da <mult_store>:
  # x in %rdi,y in %rsi,dest in %rdx
  4004da:   push   %rbx
  4004db:   mov    %rdx,%rbx		# 保存 dest,采取调用方保存
  4004de:   callq  4004d2 <mult2>	# 调用 mult2
  4004e3:   mov    %rax,(%rbx)		# 将 %rax 保存的 a * b
  									# 移动到 %rbx 保存的 dest 指针指向的内存处
  									# t 并没有实际的作用,编译器将其创建优化掉了
  4004e6:   pop    %rbx
  4004e7:   retq					

编译器优化

上面所说的都是比较小的内置类型,那假如返回的对象很大,%rax 放不下该怎么办?

下面介绍一种 C++ 对返回值的优化方式,实际编译器并不一定会使用该方式。

class qgw {
    // 有默认构造函数、拷贝构造函数、析构函数等
    long a1;
    long a2;
    long a3;
} qgw;

qgw fun() {
	qgw q;
    // 处理 q
    return q;
}

如果返回值很小,我们可以使用寄存器取到返回值,现在又该怎么办呢?Stroustrup 在 cfront 中的解决方案是一个双阶段优化:

  1. 加上一个额外参数,类型是 class object 的一个 reference
    • 这个参数在最后用 “返回值” 构建
  2. 在 return 指令之前插入一个拷贝构造调用操作,以便将想要返回的 object 的内容当做上述新增参数的初值

上述代码经转化后如下:

void fun(qgw& __result) {
	qgw q;
    // 编译器产生的默认构造函数调用操作
    q.qgw::qgw();
    // 处理 q
    // 编译器产生的拷贝构造调用操作
    __result.qgw::qgw(q);
    return;
}
qgw qin = fun();
// 转化为
// 不必为 qin 调用默认构造函数
qgw qin;
fun(qin);

// fun() 函数返回值调用 test 函数
fun().test();
// 转化为
// 编译器生成的临时变量
qgw __temp0;
(fun(__temp0), __temp0).test();

还有一种被称为 Named Return Value(NRL)优化,被视为标准 C++ 编译器的一个义不容辞的优化操作。

qgw fun() {
	qgw q;
    // 处理 q
    return q;
}

// 直接优化为
void fun(qgw& __result) {
    // 默认构造被调用
    __result.gqw::qgw();
    // 直接处理 __result
    return;
}

经上述处理后,函数没有真正意义上的返回值了,也就不需要处理大对象的情况了。

对于传参请参考:传参的理解

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

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

相关文章

Win10+GTX3060+Python+PyTorch+Tensorflow安装

本文是个备忘录&#xff0c;是折腾半个下午的成果&#xff0c;记下来免得忘记了。 0. 安装Win10&#xff0c;安装显卡驱动程序。 1. 弄清楚目前版本的PyTorch和Tensorflow支持哪个版本的Python。截至本文编写时&#xff0c;PyTorch需要Python的3.7~3.9&#xff0c;Tensorflow…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(字发生器)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;字发生器 &#xff08;1&#xff09;“控件”选项组 &#xff08;2&#xff09;“显示”选项组 &#xff08;3&#xff09;“触发”选项组 &#xff08;4&#xff09;“频率”选项组 &#xff08;5&#xff09;字符…

CSS 艺术之暗系魔幻卡牌

CSS 艺术之暗系魔幻卡牌参考描述效果支线HTML图片主线去除元素的部分默认属性定义 CSS 变量body#card自定义属性定义动画#card::before#card::afterimg代码总汇参考 项目描述MDNWeb 文档搜索引擎Bing 描述 项目描述Edge109.0.1518.61 (正式版本) (64 位) 效果 注&#xff1a;…

DaVinci:HDR 调色

调色页面&#xff1a;HDR 调色Color&#xff1a;HDR GradeHDR 调色 HDR Grade调板不仅可用于 HDR 视频的调色&#xff0c; 也可用于 SDR 视频。其调色功能与标准色轮类似&#xff0c;但能调整的区域却要细致很多&#xff0c;同时&#xff0c;它还是可感知色彩空间的工具。高动态…

41.Isaac教程--使用DOPE进行3D物体姿态估计

使用DOPE进行3D物体姿态估计 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 深度对象姿态估计 (DOPE:Deep Object Pose Estimation) 从单个 RGB 图像执行已知对象的检测和 3D 姿态估计。 它使用深度学习方法来预测对象 3D 边界框的角点和质心的…

【数据结构】单调栈、单调队列

单调栈 单调栈 单调 栈 模拟单调递增栈的操作&#xff1a; 如果栈为 空 或者栈顶元素 大于 入栈元素&#xff0c;则入栈&#xff1b;否则&#xff0c;入栈则会破坏栈内元素的单调性&#xff0c;则需要将不满足条 件的栈顶元素全部弹出后&#xff0c;将入栈元素入栈。 单调…

研究分析如何设计高并发下的弹幕系统

一、需求背景为了更好的支持直播业务&#xff0c;产品设计为直播业务增加弹幕功能,但是最初的弹幕设计使用效果并不理想&#xff0c;经常出现卡顿、弹幕偏少等需要解决的问题。二、问题分析按照背景来分析&#xff0c;系统主要面临以下问题&#xff1a;带宽压力&#xff1b;弱网…

[基础]qml基础控件

TextText元素可以显示纯文本或者富文本(使用HTML标记修饰的文本)。它有font,text,color,elide,textFormat,wrapMode,horizontalAlignment,verticalAlignment等属性。主要看下clip&#xff0c;elide&#xff0c;textFormat&#xff0c;warpMode属性clipText 项目是可以设置宽度的…

Apache Spark 机器学习 特征抽取 4-2

Word2Vec 单词向量化是一个估算器&#xff0c;将文档转换成一个按照固定顺序排列的单词序列&#xff0c;然后&#xff0c;训练成一个Word2VecModel单词向量化的模型&#xff0c;该模型将每个单词映射成一个唯一性的、固定大小的向量集&#xff0c;对每个文档的所有单词进行平均…

【数据结构和算法】实现线性表中的静态、动态顺序表

本文是数据结构的开篇&#xff0c;上文学习了关于使用C语言实现静态、动态、文件操作的通讯录&#xff0c;其中使用到了结构体这一类型&#xff0c;实际上&#xff0c;是可以属于数据结构的内容&#xff0c;接下来我们来了解一下顺序表的相关内容。 目录 前言 一、线性表 一…

流批一体计算引擎-6-[Flink]的Python DataStream API程序

参考官方Python API文档 1 IDEA中运行Flink 从Flink 1.11版本开始, PyFlink 作业支持在 Windows 系统上运行&#xff0c;因此您也可以在 Windows 上开发和调试 PyFlink 作业了。 1.1 环境配置 pip3 install apache-flink1.15.3 CMD>set PATH查看环境变量 CMD>set JAV…

对JDBC驱动注册--DriverManager.registerDriver和Class.forName(driverClass)的理解

对JDBC驱动注册–DriverManager.registerDriver和Class.forName(driverClass)的理解 JDBC提供了独立于数据库的统一API&#xff0c;MySQL、Oracle等数据库公司都可以基于这个标准接口来进行开发。包括java.sql包下的Driver&#xff0c;Connection&#xff0c;Statement&#x…

注解方式管理Bean

1.注解方式创建对象IOC 导入依赖 aop Component(父注解) 放在类上,用于标记,告诉spring当前类需要由容器实例化bean并放入容器中 该注解有三个子注解 Controller 用于实例化controller层bean Service 用于实例化service层bean Repository 用于实例化持久层bean 当不确定是哪一…

【刷题大本营】二叉树进阶oj题(动图讲解,附代码及题目链接)

&#x1f525;&#x1f525; 欢迎来到小林的博客&#xff01;&#xff01;       &#x1f6f0;️博客主页&#xff1a;✈️小林爱敲代码       &#x1f6f0;️欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言       这篇文章给大家带来一…

RK3399平台开发系列讲解(文件系统篇)文件回写过程介绍

🚀返回专栏总目录 文章目录 一、编程接口二、回写过程2.1、周期回写2.2、强制回写2.3、系统调用sync沉淀、分享、成长,让自己和他人都能有所收获!😄 📢进程写文件时,内核的文件系统模块把数据写到文件的页缓存,没有立即写回到存储设备。文件系统模块会定期把脏页(即…

[JavaEE]线程池

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1. 线程池是什么? 2. 线程池的实现原理 3. 标准…

Eureka集群构建步骤

目录 一、Eureka集群原理说明 二、EurekaServer集群环境构建步骤 三、将支付服务8001微服务发布到上面2台Eureka集群配置中 四、将订单服务80微服务发布到上面2台Eureka集群配置中 五、测试01 六、支付服务提供者8001集群环境构建 七、负载均衡 八、测试02 一、Eureka集…

论文投稿指南——中文核心期刊推荐(建筑科学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

前同事居然因为 Pycharm 的这个功能,即使离职三年也依然经常被请去喝茶~

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

教你一键生成形如Springboot的高大上banner打印效果

背景 今天闲来无聊&#xff0c;想搞一个类似于Springboot项目启动时打印效果&#xff0c;如下图&#xff1a; 问题解决方案 那这个打印效果怎么实现的呢&#xff1f; 其实&#xff0c;对于这个中效果实现起来也是很简单的。毕竟依托于Springboot强大的框架&#xff0c;任何问…