【C语言_函数栈帧_复习篇】

目录

一、什么是函数栈帧

二、什么是栈

三、相关寄存器

四、相关汇编命令

五、 解析函数栈帧的创建和销毁


一、什么是函数栈帧

在每一次函数调用之前编译器都会提前在内存的栈区为被调用的函数开辟一块空间,这块空间被称为该函数的函数栈帧,这些空间是用来存放:

① 函数参数和函数返回值

② 临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)

③ 保存上下文信息(包括在函数调用前后需要保持不变的寄存器)

二、什么是栈

在经典的计算机科学中,栈被定义为一种特殊的容器,用户可以将数据压入栈中(入栈,push),也可以将已经压入栈中的数据弹出(出栈,pop),但是栈这个容器必须遵守一条规则:先入栈的数据后出栈。压栈操作使得栈增大,而弹出操作使得栈减小。栈区开辟内存时习惯先使用高地址再使用低地址

三、相关寄存器

eax:通用寄存器,保留临时数据,常用于返回值

ebx:通用寄存器,保留临时数据

eip :指令寄存器,保存当前指令的下一条指令的地址

esp:栈顶寄存器

ebp:栈底寄存器

说明:ebp 和 esp 这两个寄存器中存放的是地址,这两个寄存器是用来维护函数栈帧的,ebp 叫栈底指针,用于记录栈底的地址,esp 叫栈顶指针,用于记录栈顶的地址。

四、相关汇编命令

push:压栈,同时esp栈顶指针要向低地址移动4字节

pop:出栈,同时esp栈顶寄存器也要向高地址移动4字节

mov:数据转移指令,将第二个参数的值赋给第一个参数

sub:减法命令

add:加法命令

call:将当前指令的下一条指令的地址压栈,并进入被调函数

jump:通过修改eip,回到主调函数函数

ret:相当于于pop eip

五、 解析函数栈帧的创建和销毁

//以下列代码为例,在VS2013中,讲解函数栈帧的创建和销毁过程
//注意:
//① 在不同的编译器下,函数栈帧的创建和销毁过程会有差异,但大体逻辑相同
//② 在VS2022等比较新的版本中,看不到细节,所以建议用更老的版本观察
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
	int a = 3;
	int b = 5;
	int ret = 0;

	ret = Add(a, b);

	printf("%d\n", ret);
	return 0;
}

Ⅰ. 通过打开[调试] --  [窗口] -- [调用堆栈],并调试代码可以发现,在VS2013中main函数其实也是被其他函数调用的,具体:main 函数被__tmainCRTStartup函数调用,__tmainCRTStartup函数是被 mainCRTStartup 函数调用的

Ⅱ. F10调试到main函数开始执行的第一行,右击鼠标点击反汇编,即可观察源代码的汇编代码

注意:VS编译器每次调试都会为程序重新分配内存,下方截图的反汇编代码是一次调试代码过程中数据,每次调试略有差异。

解析上图:栈区的开辟是从高地址向低地址开辟的,函数内部为局部变量开辟空间也是由高地址向地址开辟的,但数组内部给每个元素开辟空间的顺序是从数组低地址向高地址开辟的。由此有了如图从高地址向低地址依次开辟函数栈帧的顺序排列,

mainCRTStartup --> __tmainCRTStartup --> main --> Add,值得注意的是,栈底指针ebp和栈顶指针esp不能同时维护多个栈帧空间,只能按秩序一个个维护。

函数栈帧的创建和销毁大概过程:① 将主调函数的ebp栈底指针压栈,以便之后pop此处后ebp栈底指针回到主调函数栈底指针原来的位置 ② 为被调用的函数开辟栈帧空间,并初始化栈帧空间所有地址内部的值为cccc...这样一些随机的值③ 给函数内部的局部变量按从高地址到低地址的顺序随机分配内存空间,并初始化局部变量的值 ④ 如果被调用函数需要传参,则会在进入被调用函数之前,先将实参从右至左拷贝一份依次压栈 ⑤ 通过call汇编指令,先将主调函数当前下一行的地址压栈,以便被调函数执行完后返回此处,继续运行下一行的指令,压栈后就会进入到被调用函数的内部,接下来的步骤和上面①②③一样,如果需要用到形参里的值,则会利用指针的偏移量找到形参的位置,再进行相关运算,返回的结果最终会存放在寄存器eax中,接下来就会进行一系列的出栈操作,以便将开辟的空间释放,在此处我们可以观察到,形参的销毁是在函数调用完后才销毁的,然后才将函数调用后返回的值存入主调函数的相关变量中。

通过学习函数栈帧可以回答一些之前学习过程中疑问:

 1. 局部变量是如何创建的?

答:首先为被调用函数开辟栈帧空间,再为栈帧空间内部各地址中的值初始化CCCC...,然后才为函数内部的局部变量分配空间(从高地址向低地址利用),并存入初始化的值。

2. 为什么局部变量不初始化的时候会是随机值?

答:在为被调用函数创建栈帧空间的同时,也已经通过相关操作初始化了栈帧空间内部每个地址内部存放的值。如果局部变量写代码时就已经初始化了,原本存放在相关地址内的随机值就可以被覆盖。

3. 函数是怎么传参的,传参顺序是怎么样的?

答:在还没进入被调用函数内部前,就已经通过push把函数调用的参数从右向左拷贝一份了,当进入到被调用函数内部,会通过指针的偏移量找到形参所在的位置利用其内部的值

4. 形参和实参的关系?

答:形参确实是实参的一份临时拷贝,改变形参不会影响实参。

5. 返回值是如何带回来的

答:通过寄存器eax带回来的,是由于寄存器存在于CPU中不会被销毁。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot269反欺诈平台的建设

反欺诈平台设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装反欺诈平台软件来发挥其高效地信息处…

使用python实现一个dicom影像解析入库程序demo

简介 DICOM(Digital Imaging and Communications in Medicine)是医学图像和相关信息的国际标准。它定义了医学影像的格式和通信协议,使得不同设备和系统之间可以交换和共享医学图像和相关数据,如CT扫描、MRI图像、超声波图像等。…

19.创建帖子

文章目录 一、建立路由二、开发CreatePostHandler三、编写logic四、编写dao层五、编译测试运行 一、建立路由 这里要稍微注意的是:需要登录后才可以发表帖子,所以需要用到我们之前写的鉴权中间件。中间件对用户携带的token解析成功后,便会将…

【网络工程师进阶之路】BFD技术

个人名片:🪪 🐼作者简介:一名大三在校生,喜欢AI编程🎋 🐻‍❄️个人主页🥇:落798. 🐼个人WeChat:hmmwx53 🕊️系列专栏:&a…

[AutoSar]BSW_Com013 CAN TP 模块配置

目录 关键词平台说明一、缩写对照表二、Functional Description(vector)2.1 Asynchronous and Synchronous behavior of CanTp_Transmit2.1.1 asynchronous 2.1.2 synchronous2.2 Separation Time by Application 三、CanTpChannels3.1 接收端3.2 发送端…

初识Python语言-课堂练习【pyhton123题库】

初识Python语言-课堂练习【pyhton123题库】 一、单项选择题 1、Guido van Rossum正式对外发布Python版本的年份是: A 2008B 1998C 1991D 2002 【答案】C 【解析】暂无解析2、下面不是Python语言特点的是:‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪…

C++初阶:内存管理

目录 1. C/C中各种资源的内存分布1.1 C/C程序内存区域划分1.2 各资源的内存分布情况(练习) 2. C中的动态内存管理方式2.1 new/delete开辟内置类型空间2.2 new/delete开辟销毁自定义类型空间 3. operator new 与 operator delete函数4. new与delete的实现…

Spring MVC中的REST风格

文章目录 REST风格1 REST简介问题导入1.1 REST介绍1.2 RESTful介绍1.3 注意事项 2 RESTful入门案例问题导入2.1 快速入门2.2 PathVariable介绍2.3 RequestBody、RequestParam、PathVariable区别和应用 3 REST快速开发【重点】3.1 代码中的问题3.2 Rest快速开发 4案例&#xff1…

算法时空复杂度分析:大O表示法

文章目录 前言大O表示法3个时间复杂度分析原则常见的时间复杂度量级空间复杂度参考资料 前言 算法题写完以后,面试官经常会追问一下你这个算法的时空复杂度是多少?(好像作为一名算法工程师,我日常码代码的过程中,并没…

FreMIM:傅里叶变换与遮罩的图像建模在医学图像分割中的应用

代码链接:GitHub - Rubics-Xuan/FreMIM: This repo holds the official code for the paper "FreMIM: Fourier Transform Meets Masked Image Modeling for Medical Image Segmentation". 论文链接:https://arxiv.org/abs/2304.10864 收录于…

C#重新认识笔记_ FixUpdate + Update

C#重新认识笔记_ FixUpdate Update Update: 刷新频率不一致,非物理对象的移动,简单的刷新可用, FixedUpdate: 刷新频率一致,按照固定频率刷新,一般调用FixedUpdate之后,会立即进入必要的物理计算中,因此,任何影响刚…

springboot3 打包报错32-bit architecture x86 unsupported或者 returned non-zero result

springboot3 打包异常情况处理记录 在测试springboot3 native打包时候遇到的异常,百度和谷歌上方法都无法解决我的问题,最后记录一下我最后的原因和解决方案。 前置要求:自己处理好vs的相关内容后 报错一: [1/7] Initializing…

回归测试,有什么高效的测试方法?

什么是回归测试? 回归测试(Regression testing) 指在发生修改之后重新测试先前的测试以保证修改的正确性。理论上,软件产生新版本,都需要进行回归测试,验证以前发现和修复的错误是否在新软件版本上再次出现…

跨境电子商务支付与结算的支撑系统

​1、跨境电子商务支付与结算的核心系统。 核心系统是用户执行跨境电子商务支付的核心模块,包括以下具体流程。 ​ ​①用户从跨境电子商务支付应用启动跨境电子商务支付流程。 ②跨境电子商务支付应用根据应用和用户选择的支付工具,来调用对应的支付产…

来吧伙计们,让AI教我们怎么说海盗语

“如果想伺机而动,就是这样。”——杰克船长提到海盗,我们往往联想到约翰尼德普在《加勒比海盗》中饰演的杰克船长。我们有什么理由不喜欢海盗呢?他们航行在海上,寻找埋藏的宝藏,痛饮朗姆酒,用自己独特的海…

24考研调剂 | 武汉纺织大学

教育部重点实验室招收24年调剂生,材料、化学、机械工程、计算机、力学等相关专业 考研调剂招生信息 学校:武汉纺织大学 专业:工学->材料科学与工程 年级:2024 招生人数:100 招生状态:正在招生中 联系方式:********* (为保护个人隐私,联系方式仅限APP查看)…

springboot的maven多模块如何混淆jar包

springboot的maven多模块如何混淆jar包 一.简介二. 示例2.1 基本配置2.2 结果 三. 错误3.1 错误13.2 错误2 四. 参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱 一.简介 …

王道机试C++第6章 数学问题和22年蓝桥杯省赛选择题Day34

6.1 进制转换 二进制数(十转二) 习题描述 大家都知道,数据在计算机里中存储是以二进制的形式存储的。 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是…

个人博客系统(测试报告)

一、项目背景 一个Web网站程序,你可以观看到其他用户博客也可以登录自己的账号发布博客,通过使用Selenium定位web元素、操作测试对象等方法来对个人博客系统的进行测试,测试的核心内容有用户登录、博客列表及博客数量的展示、查看全文、写博客…

Vue-Vben-Admin:中大型项目后台解决方案及如何实现页面反向传值

Vue-Vben-Admin:中大型项目后台解决方案及如何实现页面反向传值 摘要: Vue-Vben-Admin是一个基于Vue3.0、Vite、Ant-Design-Vue和TypeScript的开源项目,旨在为开发中大型项目提供一站式的解决方案。它涵盖了组件封装、实用工具、钩子函数、动…