C语言番外-------《函数栈帧的创建和销毁》知识点+基本练习题+完整的思维导图+深入细节+通俗易懂建议收藏


绪论

        书接上回,上回我们已经将C语言的所有知识点进行了总结归纳到同一个思维导图中,而本章是一个番外篇,将具体讲述一些更深入的知识。

话不多说安全带系好,发车啦(建议电脑观看)

        附:红色,部分为重点部分;蓝颜色为需要记忆的部分(不是死记硬背哈,多敲);黑色加粗或者其余颜色为次重点;黑色为描述需要

思维导图:

 

要XMind思维导图的话可以私信哈

目录

1.函数栈帧的创建和销毁

1.1寄存器

1.2创建函数栈帧

1.3程序进程中的汇编代码

1.4函数栈帧的销毁

2.到了此处我们需要学习到的是:

2.1变量是如何创建的创建?

2.2为什么变量不初始化会是随机值?

2.3函数是怎么传参的以及传参的顺序是什么?

2.4形参和实参的关系是?

2.5函数的调用时怎么实现的?

2.6调用结束后是怎么返回的?


1.函数栈帧的创建和销毁

函数栈帧的创建和销毁在不同的编译器底下的实现都不一样(越高级的编译器越复杂,但其基本逻辑是一样的)

1.1寄存器

知识点:

寄存器是具有存储功能的一个cup内的原件

在C语言中有着多个寄存器(eax、ebx、ecx、edx、ebp、esp)但各自有着不同的功能

对于函数栈帧的创建和销毁主要要看的是下面这两个寄存器

esp(栈顶指针),ebp(栈底指针)  这两个寄存器中存放的是地址用来维护正在调用的函数的函数栈帧

细节(注意点):

  1. 每一次函数的调用过程中都会在栈帧上开辟一块空间,对于每个开辟的空间就被称作该函数的函数栈帧(如ADD函数的函数栈帧)
  2. 栈区空间的使用习惯是先使用高地址再使用低地址
  3. main主函数也是被其他函数调用的(当进入到主函数时esp、ebp就会指向主函数所借用的空间(指向正在进行的函数)具体细节我们就不再过多的追溯了)

1.2创建函数栈帧

知识点:

当进入到调用的函数的函数栈帧他会

  1. 先进行push压栈,并且把寄存器ebp指向所压的空间
  2. 然后再将esp指向和ebp一样的位置(具体看下图)
  3. 再将esp减去将要开辟的空间大小(每个函数减的大小(所开辟的空间大小)都可能不一样这取决于编译器。附:因为函数栈帧的使用习惯是先使用高地址再使用低地址的所以是减才能让寄存器所指向的位置往上走)(具体看下图)
  4. 再然后会连续push(压栈)三个寄存器进来ebx、esi、edi(这具体的细节不用去了解)
  5. 最后的4个个步骤可以概括为将所开的空间(从esp到ebp)全部置为cc cc cc cc(具体看下图)

1.3程序进程中的汇编代码

知识点:

1.当成功创建了一个栈帧后,我们对栈帧内的代码执行,此处先对 int a ,b 的初始化

具体是在ebp-8和ebp-20的位置进行mov操作,将2存放到ebp-8,将3放到ebp-20(所以说变量的创建是从栈帧中的ebp-8处开始创建第一个的,并且每次开辟的空间和上一次变量开辟的位置中间相差2个整形的空间,地址相差12)(具体看下图)

2.再到ADD函数的调用

对于前四步可以概括为从右往左的把参数进行压栈操作(将参数压栈到栈顶)(具体看下图)

3.call调用该函数,并且记住call指令后的下一条指令的地址进行压栈,后面可以通过压栈内的地址就可以找回然后继续往下进行程序(具体看下图)

1.4函数栈帧的销毁

知识点:

当我们进入到ADD函数后,要经历和main函数一样的函数栈帧创建过程:

具体我就不再讲述了和main函数一样的操作(ebp压栈、改变esp、再ebx esi edi压栈、再将开辟的空间赋值成cccccccc) 

 

细节:

进入到ADD函数的语法部分

1.首先对z的初始化

第一个变量的位置ebp-8处存放z  = 0(具体看下图)

 

2.其次进行z = x + y 的赋值

先将之前压好的数据(ebp+8)移动到寄存器eax上

再加上另一个之前压好的值(ebp + c处的数据( c是十六进制就是表示ebp + 12))

最后再把这个寄存器上的值存进z = 5(具体看下图)

3.最后返回

 再把z位置上的值(ebp-8)存放到eax上(如果不存的话当栈帧的销毁会导致数据的丢失)(具体看下图)


 说了这这么多上面都是在讲述一些汇编代码,

下面才是一个栈帧的销毁

  1. 首先将edi esi ebx 这些之前压栈的进行出栈操作(具体看下图)
  2. 然后把esp移动到ebp所指向的位置(ADD的栈底)
  3. 然后后因为ebp的出栈,所以会让ebp返回之前函数的底部(因为一开始对main函数的ebp进行了压栈,会把压栈里的值附给此处的ebp)
  4. 然后esp因为ebp的出栈就会指向一开始存好的call指向下一条指令的地址所压的栈上
  5. 当进行ret会把该处进行pop处理所以esp就会指向之前压栈的两个形参ecx、eax,而程序会得到了call指令的下一条指令的地址就会接着从下一条指令开始往下执行
  6. 回来后再对esp + 8 就会重新指回main函数的顶部

 

最后再把存放在eax中的z的值存放到c开辟的空间处

后面再进行printf的打印以及mian函数栈帧的摧毁即可

对此就不再过多的追究了都是一些汇编代码的问题以及和ADD函数一样的栈帧的摧毁问题


2.到了此处我们需要学习到的是:

2.1变量是如何创建的创建?

先通过ebp、esp两个寄存器进行压栈和esp的减去一定的值再对该区初始化后在这开辟好的栈帧空间内分配一定空间给该局部变量

2.2为什么变量不初始化会是随机值?

因为在局部变量放进去之前,已经对该区域的数值进行了随机的存放,如果该变量没有初始化,那么该变量的值就等于当初随机存放好的值(cc cc cc cc)(所以我们应该初始化把随机进行覆盖)

2.3函数是怎么传参的以及传参的顺序是什么?

当传参时是将参数从右向左的把参数进行压栈压到栈顶,后面直接从ebp+8 ..... 进行取数据

2.4形参和实参的关系是?

因为是压栈的,压栈就意味着开辟一块新的空间只是把实参的数据拷贝了过来,所以说在传值调用时改变形参不影响实参

2.5函数的调用时怎么实现的?

之前的call、ret来进行的(具体上面已经写过)

2.6调用结束后是怎么返回的?

通过寄存器eax进行保存返回的结果

持续更新细致内容,三连关注哈

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

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

相关文章

我用Python django开发了一个商城系统,已开源,求关注!

起始 2022年我用django开发了一个商城的第三方包,起名为:django-happy-shop。当时纯粹是利用业余时间来开发和维护这个包,想法也比较简单,Python语言做web可能用的人比较少,不一定有多少人去关注,就当是一个…

我们在操作自动化测如何实现用例设计实例

在编写用例之间,笔者再次强调几点编写自动化测试用例的原则: 1、一个脚本是一个完整的场景,从用户登陆操作到用户退出系统关闭浏览器。 2、一个脚本脚本只验证一个功能点,不要试图用户登陆系统后把所有的功能都进行验证再退出系统…

【开发】后端框架——Dubbo

前置知识: 微服务 Dubbo是高性能的RPC框架,主要目的是支持远程调用 Dubbo Dubbo是一个 高性能和透明化的RPC框架 ,主要目的是支持远程调用,是阿里巴巴SOA服务化治理方案的核心框架 最大的特点是按照分层的方式来 架构 &#xff0c…

LDNet分割模型搭建

原论文:https://arxiv.org/abs/2110.09103源码:https://github.com/unilight/LDNet 直接步入正题~~~ 一、ESA_blcok模块 1、PPM模块 class PPM(nn.Module):def __init__(self, pooling_sizes(1, 3, 5)):super().__init__()self.layer nn.ModuleList…

蓝桥杯刷题冲刺 | 倒计时13天

作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.母牛的故事2.魔板1.母牛的故事 题目 链接: [递归]母牛的故事 - C语言网 (dotcpp.c…

基于微信小程序+爬虫制作一个表情包小程序

跟朋友聊天斗图失败气急败坏的我选择直接制作一个爬虫表情包小程序,从源头解决问题,从此再也不用担心在斗图中落入下风 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一、API1.1 项目创建1.2 图片爬虫帮助类1.3 测试窗体1.4 接口封装二、小程序2.1 项…

【iOS】GCD再学

文章目录前言GCD概要什么是GCD多线程编程GCD的APIDispatch Queuedispatch_queue_createMain Dispatch Queue/Global Dispatch Queuedispatch_set_target_queuedispatch_afterDispatch Groupdispatch_barrier_asyncdispatch_syncdispatch_applydispatch_suspend/dispatch_resume…

网络安全 2023 年为什么如此吃香?事实原来是这样....

前言由于我国网络安全起步晚,所以现在网络安全工程师十分紧缺。俗话说:没有网络安全就没有国家安全为什么选择网络安全?十四五发展规划建议明确提出建设网络强国,全面加强网络安全保障体系和能力建设,加强网络文明建设&#xff0c…

多线程(三):Thread 类的基本属性

上一个篇章浅浅了解了一下 线程的概念,进程与线程的区别,如何实现多线程编程。 而且上一章提到一个重要的面试点: start 方法和 run 方法的区别。 start 方法是从系统那里创建一个新的线程,这个线程会自动调用内部的run 方法&…

瑟瑟发抖吧~OpenAI刚刚推出王炸——引入ChatGPT插件,开启AI新生态

5分钟学会使用ChatGPT 插件(ChatGPT plugins)——ChatGPT生态建设的开端ChatGPT插件是什么OpenAI最新官方blog资料表示,已经在ChatGPT中实现了对插件的初步支持。插件是专门为以安全为核心原则的语言模型设计的工具,可帮助ChatGPT…

JSON 教程导读

JSON 教程导读在开始深入了解JSON知识之前,让我们先了解什么是JSON!JSON: JavaScript Object Notation(JavaScript 对象表示法) JSON 是存储和交换文本信息的语法,类似 XML。JSON 比 XML 更小、更快,更易解析。JSON实例&#xff1…

CODESYS增量式PID功能块(ST完整源代码)

增量式PID的详细算法公式和博途源代码,请参看下面的文章链接: 博途1200/1500PLC增量式PID算法(详细SCL代码)_博图scl语言pid增量编码器_RXXW_Dor的博客-CSDN博客SMART200PLC增量式PID可以参看下面这篇博文,文章里有完整的增量式PID算法公式,这里不在赘述西门子SMARTPLC增量…

你值得拥有——流星雨下的告白(Python实现)

目录1 前言2 霍金说移民外太空3 浪漫的流星雨展示 4 Python代码 1 前言我们先给个小故事,提一下大家兴趣;然后我给出论据,得出结论。最后再浪漫的流星雨表白代码奉上,还有我自创的一首诗。开始啦:2 霍金说移民外太空霍…

你的应用太慢了,给我司带来了巨额损失,该怎么办

记得很久之前看过谷歌官方有这么样的声明:如果一个页面的加载时间从 1 秒增加到3 秒,那么用户跳出的概率将增加 32%。 但是早在 2012 年,亚马逊就计算出了,页面加载速度一旦下降一秒钟,每年就会损失 16 亿美元的销售额…

杨辉三角形 (蓝桥杯) JAVA

目录题目描述:暴力破解(四成):二分法破解(满分):题目描述: 下面的图形是著名的杨辉三角形: 如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如…

如何编写测试用例?

带着问题学习是最高效的学习方法。 因此,在介绍如何编写测试用例之前,先看一个软件系统登录功能的测试(如下截图所示): 要做这个登录页面的测试用例,你会从哪些方面思考进行测试呢? 看似简单的…

【C语言蓝桥杯每日一题】—— 货物摆放

【C语言蓝桥杯每日一题】—— 货物摆放😎前言🙌排序🙌总结撒花💞😎博客昵称:博客小梦 😊最喜欢的座右铭:全神贯注的上吧!!! 😊作者简介…

图话第一代女性开发者

写在前面的话想问大家一个有趣的问题,大家知道我们程序员圈的第一位女性开发者是谁吗?作为开发者,以前并没有认真去想过这个问题,这两天认真的看了一下百度百科查找了一下相关的专业知识。才知道历史上第一位女性程序员是&#xf…

docker+jenkins+maven+git构建聚合项目,实现自动化部署,走了800个坑

流程 主要的逻辑就是Docker上安装jenkins&#xff0c;然后拉取git上的代码&#xff0c;把git上的代码用Maven打包成jar包&#xff0c;然后在docker运行 这个流程上的难点 一个是聚合项目有可能Maven install的时候失败。 解决办法&#xff1a;在基础模块的pom文件上添加 <…

重谈“协议” + 序列化和反序列化

目录 1、重谈 "协议" 协议的概念 结构化数据的传输 序列化和反序列化 2、网络版计算器 2.1、服务端serverTcp.cc文件 服务端serverTcp.cc总代码 2.2、客户端clientTcp.cc文件 客户端clientTcp.cc总代码 2.3、协议定制Protocol.hpp文件 服务端需要的协议 客户端需要…