当前位置: 首页 > news >正文

C++:函数传参到函数执行结束发生了什么

首先要明确两个概念

  • 函数实参的入栈从右向左
  • 栈区从高地址向低地址偏移

接下来看下面一段代码

void fun(int a,int b,int c){std::cout<<&a<<" "<<&b<<" "<<&c<<std::endl;
}
int main(){fun(1,2,3);
}

这段代码看起来很简单但是你在不同环节下运行起来可能就会有问题了windows下vs
在这里插入图片描述
linux下vscode
在这里插入图片描述
可以看出一个是从左向右递增,一个是从左向右递减,你觉得这个是为什么呢?

我也不卖关子了,出现这种情况的原因是不同编译器将帧地址传递给函数后对函数局部变量的处理顺序不同。

函数从调用开始到结束过程

创建栈帧

在编译期编译器会根据类中局部变量的使用情况确定栈帧的大小

主函数帧指针
主函数内局部变量
返回地址
函数的帧指针(指向主函数帧指针)
函数的局部变量
栈指针

以上就是一个主函数调用一个函数时栈内的情况,栈帧可以理解为一个函数的活动空间,或者说运行环境,下面简述几个概念。

  • 帧指针:函数的主心骨,局部变量的创建都是在它的地址基础上偏移,它内部存函数调用者的帧指针地址
  • 栈指针,就是栈顶
  • 返回地址,存储调用函数完成后需要返回到的下一条指令的地址

栈帧的大小是在编译期间确定的,形参也处于局部变量的范畴,将实参从调用者的栈帧内移动到被调用者的栈帧内就涉及到了几种传参方式

  • 值传递
  • 址传递
  • 引用传递(也是通过址传递)

栈帧和代码区函数的交互

函数的运行在代码区,平时看汇编的时候如果你注意就会发现发生函数调用时一定会传一个东西,这个东西就是帧指针,比如下面这一坨

#include<iostream>
using namespace std;
void fun(){int nums[1024];
}int main() {fun();
}
fun():push    rbpmov     rbp, rspsub     rsp, 3976nopleaveret
main:push    rbpmov     rbp, rspcall    fun()mov     eax, 0pop     rbpret

这个rbp寄存器里面存的就是这个帧指针,sub rsp, 3976这个条指令就是进行栈指针的偏移,这个3976是栈帧内为局部变量预留的空间,至此可以说栈帧的创建完成了,接下来该使用了,局部变量的创建可以看到都是通过在rbp的基础上进行偏移的,需要注意的是编译器会进行各种优化你需要编译时加上-0o关闭优化,还有就是栈的对齐方式是16字节。

所以说当面试官问你栈区有没有产生内存碎片的可能时,你可以从容的回答栈的对齐大多数采用的是16字节可能会因为对齐方式而产生比较多的内存碎片,这些碎片显然是用不了的,高性能的代价往往是高内存消耗。

返回值的处理

一般来说对于返回值是函数的调用者需要关注的东西,现在的大部分编译器返回值的传递其实都是通过寄存器完成的,在不进行各种优化的情况下编译器会根据返回值的数据进行选择,如果数据量较大就使用寄存器返回地址,如果数据量较小则直接使用寄存器将结果返回,寄存器返回后会调用者的栈帧内拷贝一份函数的返回值,这个过程发生在函数栈帧被释放前,这个过程结合我之前的一篇文章:C++:完美转发和移动语义看会比较清楚。
上面那个过程显然不太合理,首先返回值不是被调用者需要考虑的东西,如果说我们直接在函数调用前在调用者的栈帧内创建好被调用者的返回值然后使用寄存器将这个地址传过去,在这个地址的基础上函数再进行处理不就行了吗?实际上这个就是RVO优化的原理,此外RVO还会判断返回值有没有被用到,如果没用的话也是会优化掉的。

RVO发生的条件通常是:在函数中创建了一个局部对象,并将其作为函数返回值,而调用方直接使用了这个返回值。在这种情况下,编译器可以直接将该局部对象放置到调用方期望的位置,而不需要进行复制或移动操作。

RVO失效情景

  • 返回多个对象: 如果函数返回多个对象,而不是一个单独的临时对象,那么RVO优化可能不适用。RVO通常仅适用于返回单个对象的情况
return pair<pair<int,int>,pair<int,int>>();
  • 虚函数调用: 当函数是虚函数时,编译器可能无法确定函数返回的对象的确切类型,从而阻止了RVO优化的应用
struct A{virtual A fun(){return *this;}};
struct B:public A{virtual B* fun(){return *this;}};
A* b=new B;
b->fun();
  • 复杂的返回逻辑
if(a) return a;
else if(b) return b;
return c;

观测RVO优化的过程,直接从上下文地址的变化非常直观

A get(){A a;cout<<&a<<endl;return a;
}int main() {A a;cout<<&a<<endl;a=get();A b;cout<<&b<<endl;
}

在这里插入图片描述
可以看到当发生RVO优化时会在调用者的栈帧内临时申请一块空间,生命周期过了就被下一个变量覆盖了,现在你应该对RVO和临时对象有了新的认识

总的来说,移动语义的引入可以说从根源上缓解了临时对象对程序性能的影响,就业务中可能出现的各种情况编译器可能不能很好的进行各种优化,所以合适的代码书写还是很有必要的,不要寄希望于各种优化了

栈帧的释放

返回值处理完成后,首先帧指针跳转到上一个节点然后栈指针向高地址偏移,直到遇到返回地址程序接着运行

回归到开头时候的问题,现在你大概已经直到答案了,没错就是不同操作系统在不同编译器下函数对参数的处理顺序不同造成的。

相关文章:

C++:函数传参到函数执行结束发生了什么

首先要明确两个概念 函数实参的入栈从右向左栈区从高地址向低地址偏移 接下来看下面一段代码 void fun(int a,int b,int c){std::cout<<&a<<" "<<&b<<" "<<&c<<std::endl; } int main(){fun(1,2,3); }…...

QT中dumpcpp以及dumpdoc使用

qt中调用COM的方式方法有四种&#xff0c;参考解释在 Qt 中使用 ActiveX 控件和 COM (runebook.dev) 介绍dumpcpp的使用方法Qt - dumpcpp 工具 (ActiveQt) (runebook.dev)&#xff1a; 在安装好了的qt电脑上&#xff0c;通过powershell窗口来实现&#xff0c;powershell比cmd要…...

RPM与DNF的操作实践

这几课有三个目标&#xff1a; 第一步&#xff1a;先配置软件源 跳转到yum.repos.d目录&#xff0c;用vim创建一个openeuler_x84_64.repo文件。这个文件就是我们将会用到的软件源。 我们在里面添加这些东西&#xff0c;保存并退出即可。 然后&#xff0c;我们用yum list all就…...

车道线检测之LaneNet

论文&#xff1a;Towards End-to-End Lane Detection: an Instance Segmentation Approach Github&#xff1a;https://github.com/MaybeShewill-CV/lanenet-lane-detection?tabreadme-ov-file 论文提出一种车道线检测网络LaneNet&#xff0c;该网络以enet为主干网络结构&…...

MySQL连接数不足导致服务异常GetConnectionTimeoutException

文章目录 场景复现解决方案一、调整连接数二、优化程序 场景复现 已经上线正常运行的项目突然很多功能无法使用&#xff0c;查看程序日志发现MySQL报错&#xff0c;异常信息: Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.Ge…...

软考76-上午题-【面向对象技术3-设计模式】-创建型设计模式01

一、创建型设计模式一览 二、创建型设计模式 2-1、创建型设计模式的概念 一个类创建型模式使用继承改变被实例化的类&#xff1b; 一个对象创建型模式将实例化委托给另一个对象。 对应java的new一个对象。 2-2、简单工厂模式&#xff08;静态工厂方法&#xff09; 简单工厂…...

Matlab 双目相机标定(内置函数)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 相机标定的目的就是要找到从世界坐标转换为图像坐标所用到的投影P矩阵各个系数(即相机的内参与外参)。具体过程如下所述: 1、首先我们需要获取一个已知图形的图像(这里我们使用MATLAB所提供的数据)。 2、找到同…...

【博客7.4】缤果Qt5_TWS串口调试助手V2.0 (高级篇)

超级好用的Qt5_TWS耳机串口调试助手 开发工具: qt-opensource-windows-x86-5.14.2 (编程语言C) 目录 前言 一、软件概要&#xff1a; 二、软件界面&#xff1a; 1.App演示 三、获取 >> 源码以及Git记录&#xff1a; 总结 前言 串口调试助手支持常用的50bps - 10M…...

CSS案例-4.padding导航栏练习

效果 相关数据: 上边框:3px,颜色#ff8500 下边框:1px,颜色#edeef0 背景颜色:#fcfcfc 高度:41px 内边距20px 字体颜色#4c4c4c 知识点 盒子边框border 属性 作用 border-width 定义边框粗细,单位px border-style 边框的样式 border-color 边框颜色 边框样式...

5.1.4.2、【AI技术新纪元:Spring AI解码】Llama2 Chat

Llama2 Chat Meta 的 Llama 2 Chat 是 Llama 2 系列大型语言模型的一部分。它在基于对话的应用程序中表现出色,参数规模范围从 70 亿到 700 亿不等。利用公共数据集和超过 100 万次人类注释,Llama Chat 提供了上下文感知的对话。 通过从公共数据源获取的 2 万亿标记进行训练…...

后台发送GET/POST方法

前言: 1,get请求 2,post请求 3,post,get通用方法 4,其他的get,post写法 正文: 1,get请求 import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import or…...

计算机考研|双非一战135上岸,408经验分享+复盘

计算机专业的同学真的别想的太天真&#xff01; 相比于其他专业&#xff0c;计算机专业的同学其实还是很有优势的 但是现在随着计算机专业的同学越来越多&#xff0c;找工作的困难程度以及学历自然而然被卷起来了 以前的算法岗基本要求在本科以上&#xff0c;现在基本都是非92研…...

低代码与数字化工具:重塑软件开发的新范式

随着信息技术的飞速发展&#xff0c;软件开发已成为推动数字化转型的核心力量。在这个变革的时代&#xff0c;低代码与数字化工具逐渐崭露头角&#xff0c;它们不仅简化了开发过程&#xff0c;还大大提高了开发效率&#xff0c;成为推动软件开发领域变革的重要力量。 低代码&am…...

如何使用 ArcGIS Pro 生成TIN

三角网是一种常用于表示地表地形的数字地球模型&#xff08;DEM&#xff09;方式&#xff0c;我们可以通过 ArcGIS Pro 将等高线和高程点转换为TIN&#xff0c;这里为大家介绍一下转换方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的高…...

你真的会做抖音小店吗?你做抖店的方法是正确的吗?教学分享

大家好&#xff0c;我是电商花花。 新的一年&#xff0c;不少做抖店的商家都会产生一个疑问&#xff0c;2024年抖音小店无货源还能继续做吗&#xff1f; 做无货源模式还会被处罚吗&#xff1f; 先说答案&#xff0c;2024年抖音小店无货源能做&#xff0c;不仅能做且仍然是抖音…...

ssh免密登陆更换目标主机后无法连接

在进行hadoop分布式环境搭建时&#xff08;三台机&#xff0c;master&#xff0c;slave1&#xff0c;slave2&#xff09;&#xff0c;后期slave2系统出现问题&#xff0c;更换新机后&#xff0c;master与slave2文件传输失败&#xff1a; 以为是秘钥过期的问题&#xff0c;更换…...

Java获取视频封面图,利用FFmpegFrameGrabber获取视频封面图

依赖 <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.9</version></dependency>传入视频流获取图片byte /*** 获取视频截图** param frameNumber 视频的指定帧数* param …...

pycharm @NotNull parameter ‘module‘ of ...

下载了最新pycharm &#xff0c;无法启动运行 pycharm或者idea中Run/Debug Python项目报错 Argument for NotNull parameter ‘module‘ of … 解决方案 删除项目根目录的 idea 文件夹 随后重启&#xff0c;重新配置即可...

Python使用pynput模块后台监控鼠标及按键

Pynput 是一个 Python 第三方库&#xff0c;它提供了监听和控制键盘和鼠标事件的功能。使用 pynput&#xff0c;我们可以编写自动化脚本&#xff0c;监控输入设备的活动&#xff0c;或者实现一些与键盘和鼠标相关的功能。 一、功能说明 这段代码是运用pynput库实现对鼠标和键盘…...

C语言 扫雷游戏

写了这么长时间的关于C语言的基础知识&#xff0c;相信大家已经学会了使用C语言书写一些基础的代码&#xff0c;上次还编写了三子棋游戏的代码&#xff0c;这次我将编写一个基础版的扫雷游戏。 首先&#xff0c;创建三个文件&#xff0c;两个源文件&#xff0c;一个头文件&…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...