栈帧详解——C语言进阶

article/2025/10/18 22:26:03

目录

    • 传统艺能😎
    • 过渡区🤣
    • 正片开始👀
    • 寄存器👏
    • main函数创建👏
    • 局部变量创建👏
    • 函数部分👏
    • 形参与实参👏

传统艺能😎

小编是大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】点我!点我!请搜索博主 【知晓天空之蓝】或扫码进入!
乔乔的gitee代码库(打灰人 )欢迎访问,点我!
在这里插入图片描述

(https://blog.51cto.com)感谢支持!

过渡区🤣

现在是北京时间10:38,平平淡淡的一天,刚上完高数回来,数学课混了条狗子进来,在旁边过道蹲着再现忠犬八公,事实证明,狗都在学高数,我还不能寄。
在这里插入图片描述

正片开始👀

今天来讲讲我对栈帧创建与销毁的拙见。
理解什么是栈帧首先知道什么是栈:

在数据结构中, 栈是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

栈有什么用?

在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且存在有限栈容量,会出现溢出现象程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而弹出操作使栈减小。
栈用于维护函数调用的上下文,离开了栈函数调用就没法实现。

讲到这里,小朋友你是否有很多问号?那打住,我们抛开无聊的学术前文,另起炉灶。

寄存器👏

要讲清楚栈帧就必须理解一手寄存器。尤其是 ebp,esp这2个寄存器中存放的地址,这两个地址是用来维护函数栈帧的。
在这里插入图片描述

寄存器有很多种这里不赘述
在这里插入图片描述

main函数创建👏

我们这里随便搞一个最简单的Add函数

int   add(int x,int y)
{int z;z=x+y;return z;
}int main()
{int  data1;int  data2;int  ret;while(1){int data1,data2 = 0;scanf("%d %d",&data1,&data2);add(data1,data2);return 0;
}

搞栈帧的话我的编译器是不适合的,我是vs2019,因为编译器越高级函数的封装越复杂周密,不容易我们去剖析栈帧,我就尽量语言表达严谨一点吧。编译器反汇编过程就能反应我们栈帧创建的过程,这是我在网上找的反汇编页面可以参考一下
在这里插入图片描述
其中反汇编用到的指针我们要清楚意义:
在这里插入图片描述

在编译器中,main函数也是会被其他函数调用的,调用堆栈窗口后反汇编可以看到如下字样:

main
_tmainCRTStartup
mainCRTStartup

后面两句意义不明的玩意儿就是在调用main函数。为什么要讲这个呢?我们说每一次函数调用都要分配空间,main函数不例外也要分配栈帧空间。
以下内容和上面汇编指令表食用更佳:
首先 push ,即压栈,就是往栈sei东西进去。push 会让esp让低地址走,就会在原先基础上压进来一个 ebp 指针。
在这里插入图片描述

接下是 mov 指针,mov把后面的指针赋到前面去,esp给了ebp,也就是相当于在移位。
在这里插入图片描述
接下来是 sub 减法操作,减去一个内容来使esp指针走向低地址来开辟main函数栈帧。
在这里插入图片描述

过程模拟如下:

在这里插入图片描述

局部变量创建👏

接下来esp已经走到那几个内容的头上去了,这时出现了 lea 指针,即 load effective address 加载有效地址,其实在这个指针指定对象里面放入一个地址
在这里插入图片描述
我们后面的 [ebp-0C0h],其实就是刚刚 sub操作,本质上还是原来开辟栈帧起点 ebp 的地址,把这个地址放入edi 里面。
在这里插入图片描述

接下来的连续 mov 时在把从edi 开始的 30h 这么多个空间里面的 dword(double word-四字节数据)全部初始化成 eax 里面 “0CCCCCCCCh”的内容,保证为main函数预开辟的内存全变成 “CCCCCCCCh”,这么说来改的还是蛮多的。
接下来当我们创建变量时,比如 int a = 10;就会出现类似下面字样:

int a = 10;                      
00C2142E C7 45 EC 0A 00 00 00 mov             dword ptr [ebp-8h],0Ah

这里就是在创建局部变量了, ebp指针减了 8h,这个 8h 就是给a留的位子**(这里的 h 是编译器给的标识,我们只需要明白这是一个十六进制数)**就行了。所以总结一下,其实创建方式与main函数没有太大出入。

函数部分👏

Add函数传参时也是在将 esp 进行压栈,但注意,这时的esp里面的值是 10,相当于是在传 10 这个值。传完参紧接着就会调用函数

00C2144B E8 91 FC FF FF           call             00C210E1

call 指针作用就是调用函数,F11 执行call指令后会发现在跳转到作用域的同时,他会把 call指令的下一条指令的地址传到里面,从顶上压进来一个main函数的 ebp ,这时 esp 会继续往上面跑,一但函数执行完后返回值就会很自然的回到该地址。
在这里插入图片描述

在main函数的 ebp 上面又会传统艺能,以相同的方式开辟 Add 函数的空间,又初始化成全 c,以相同方式创建临时变量……
这时你可能会注意到传进函数的 x,y去哪里了?其实已经为他准备好了,在返回进行下一项指令时,x,y就会乖乖跑到这片空间储存
在这里插入图片描述
Add函数完成后回把传的参返回, 就是我们的 pop 指针,即出栈,这里参数每从栈顶pop一次 esp 指针就会上移一个单位,ebp也会随之退回一个单位,利用指针的偏移量找回他的形参,最后返回值ret,其逻辑本质上就是弹出main ebq那里的下一项指令的地址。
我们走出函数后,esp,ebq会回收,这时这块空间就会直接销毁,挫骨扬灰。
这样整个函数部分就完美的呈现出来了。

形参与实参👏

形参确实是我在压栈时开辟的空间,这个空间他是独立的,只有值是相同的,形参本质上是实参的一份临时拷贝,改变形参并不影响实参,那返回值是怎么带回来的呢?答:是通过寄存器。

今天先到这里,摸了家人们。


http://chatgpt.dhexx.cn/article/5abJuefc.shtml

相关文章

栈帧结构详解

前言 Java虚拟机以方法作为基本的执行单位,“栈帧”是用于支持虚拟机进行方法调用和执行的数据结构,每一个方法从调用开始到执行结束,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程,栈帧也是虚拟机运行时数据区中虚拟机栈的栈…

浅谈栈帧

一、 什么是栈帧? 什么是栈帧,首先引用百度百科的经典解释:“栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。 实际上,可以简单理解为:栈帧就是存储在用户栈上的(当然内…

栈帧(Stack Frame)

0x01.栈在计算机中的应用 在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且…

什么是栈帧

栈帧浅析 什么是栈帧 引用百度百科中的解释: 栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。函数的每次调用,都有它自己独立的栈帧。栈帧中维持着函数调用所需要的各种信息,包括函数的入参、函数的局部变…

【详解】函数栈帧——多图(c语言)

目录 前言 一.函数栈帧是什么? 二、栈帧准备知识 1.内存分区 2.什么是栈? 3.esp,ebp,eax寄存器 三、详解栈帧创建与销毁全过程 调用函数之前: 将传入函数的值放入栈中 函数执行: 1.保护当前ebp 2.…

【mcuclub】模数转换ADC0832

一、实物图 二、原理图 编号名称功能1CS片选使能,低电平芯片使能。2CH0模拟输入通道0,或作为IN/-使用。3CH1模拟输入通道1,或作为IN/-使用。4GND电源地5DI数据信号输入,选择通道控制。6DO数据信号输出,转换数据输出。7…

[技术讨论] [DDS] AD9833原理介绍及chiliDDS驱动分享(上)

​ 其实本文还有另一标题:《AD9833调不通?看这篇**就够了》 总觉字里行间隐隐霸气外露,不符合作者低调的风格,于是换了个朴素标题。标题狂不狂暂且不评,作者水平有限却是个事实;看到这篇**是你我缘分&…

ADC0832的使用

百度搜索ADC0832 Datasheet便可以免费获取该芯片的权威数据手册。 最重要的是查看它的时序及对应英文词组的意思。 CLK为时钟信号,需要外部输入,可直接与单片机引脚相连 Chip Select(CS):从Timing图中可以看出芯片工作期间要保持…

ADC0832的AD模数转换原理及编程

✅作者简介:嵌入式领域优质创作者,博客专家 ✨个人主页:咸鱼弟 🔥系列专栏:单片机设计专栏 目录 一、描述 二、模数转换原理: 三、模数转换的过程: 四、八位串行A/D转换器ADC0832简介&…

ADC0809的使用

一、前言介绍 使用ADC0809对一个模拟电压进行转换转换后的电压使用数码管显示出来 二、ADC0809的介绍 1、ADC0809简介 ADC0809是采用COMS工艺制造的双列直插式单片8位A/D转换器。分辨率8位,精度7位,带8个模拟量输入通道,有通道地址译码锁…

基于STM32F103RCT6的AD9833驱动开发(代码可以免费发邮箱)

基于STM32F103RCT6的AD9833驱动开发(代码可以免费发邮箱) AD9833手册分析 管脚定义: 手册就先讲到这里,不明白的欢迎评论区留言,另外我会把代码还有手册一并发送给感兴趣的朋友。 AD9833典型应用电路&#x…

AD9833数字信号发生器模块

简 介: 本文记录了使用快速制版测试AD9833这款数字信号发生器的内容。 关键词: AD9388,数字信号发生,快速制版 基于AD9833的正弦波,三角波,方波频率发生模块可以通过ZIGBEE来完成输入输出控制。其中还包括有…

STM32驱动AD9833模块

STM32驱动AD9833模块 前言软硬件准备一、本次使用的硬件二、代码 链接 前言 淘宝上买了个AD9833模块,stm32用商家的例程代码可以调频,可以调相,就是调不了幅度。换了几块不同32开发板都不行,重新以正点原子F103的工程为基础把驱动…

AD9833信号波形谐波

AD9833产生高频信号的谐波 ~ AD9833是一款AnalogDevices公司提供的数字信号可编程信号发生器芯片。它一般配有外置的主时钟信号,每次时钟信号将将内部28位的相位累加器递增一个相位数值。该相位数值由芯片SPI串口被外部的MCU设置。 相位累加器的高12位选择内部4096…

51驱动AD9833

使用51驱动AD9833模块的使用 关于AD9833相关参数程序流程代码片上传程序总结 原文链接:https://www.yourcee.com/newsinfo/2925703.html 关于AD9833 AD9833是一款低功耗、可编程波形发生器,能够产生正弦波、三角波和方波输出。各种类型的检测、信号激励…

Arduino + AD9833 波形发生器

Arduino SI5351 方波发生器_姜戈12的博客-CSDN博客SI5351 方波发生器https://blog.csdn.net/jiangge12/article/details/125815044 感觉 Si5351 只有方波还是少点意思。 看到有人做 AD9833 ,成品卖355元。https://www.bilibili.com/video/av463721457/ 上面视频…

[技术讨论][DDS] AD9833原理介绍及chiliDDS驱动分享(上)

其实本文还有另一标题:《AD9833调不通?看这篇**就够了》 总觉字里行间隐隐霸气外露,不符合作者低调的风格,于是换了个朴素标题。标题狂不狂暂且不评,作者水平有限却是个事实;看到这篇**是你我缘分&#xff…

STM32单片机TFT显示AD9833 DDS信号发生器语音播报正弦波方波三角波

实践制作DIY- GC0146---TFT显示AD9833 DDS信号发生器 基于STM32单片机设计---TFT显示AD9833 DDS信号发生器 二、功能介绍: 硬件组成:STM32F103C系列最小系统板 1.8寸TFT彩屏AD9833信号模块4*4矩阵键盘DY-SV17F语音播报模块 1.通过4*4键盘来设定频率值和…

失真很大的波形发生器AD9833

波形发生器AD9833 01 波形发生器 一、AD9833 AD9833是一款AnalogDevices公司提供的数字信号可编程信号发生器芯片。 它一般配有外置的主时钟信号,每次时钟信号将将内部28位的相位累加器递增一个相位数值。 该相位数值由芯片SPI串口被外部的MCU设置。  相位累加器…

【STM32+cubemx】0030 HAL库开发:DDS芯片AD9833实现简单的波形发生器

大家好,我是学电子的小白白,今天带大家了解一款波形发生器芯片——AD9833。 AD9833是AD公司出品的一款DDS波形发生器,能够产生正弦波、三角波和方波输出。 1)什么是DDS 通俗来讲,DDS是一种把波形预先存储在芯片内部的…