iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言进阶栈帧示例详解教程
  • 511
分享到

C语言进阶栈帧示例详解教程

2024-04-02 19:04:59 511人浏览 薄情痞子
摘要

目录正片开始栈有什么用?寄存器main函数创建局部变量创建函数部分形参与实参正片开始 今天来讲讲我对栈帧创建与销毁的拙见。理解什么是栈帧首先知道什么是栈: 在数据结构中, 栈是限定仅

正片开始

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

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

栈有什么用?

在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括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会回收,这时这块空间就会直接销毁,挫骨扬灰。
整个函数部分就完美的呈现出来了。

形参与实参

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

以上就是C语言进阶栈帧示例详解教程的详细内容,更多关于C语言栈帧的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言进阶栈帧示例详解教程

本文链接: https://www.lsjlt.com/news/139370.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言进阶栈帧示例详解教程
    目录正片开始栈有什么用?寄存器main函数创建局部变量创建函数部分形参与实参正片开始 今天来讲讲我对栈帧创建与销毁的拙见。理解什么是栈帧首先知道什么是栈: 在数据结构中, 栈是限定仅...
    99+
    2022-11-13
  • C语言函数栈帧详解
    目录前言一.函数栈帧是什么?二、栈帧准备知识1.内存分区2.什么是栈?三、详解栈帧创建与销毁全过程调用函数之前:将传入函数的值放入栈中函数执行:1.保护当前ebp2.创建所需调用函数...
    99+
    2022-11-12
  • C语言超详细解析函数栈帧
    目录一、前面二、预备知识三、栈帧创建与销毁四、总结一、前面 本章将以汇编视角看函数栈帧的内存是如何使用与回收的,为了降低汇编语言的理解成本,以图示的方式讲解每一步汇编指令所带来的效果...
    99+
    2022-11-13
  • C语言实现栈的示例详解
    目录前言一. 什么是栈二. 使用什么来实现栈三. 栈的实现3.1 头文件3.2 函数实现3.3 完整代码四. 栈的用处前言 前一段时间,我们试着用C语言实现了数据结构中的顺序表,单链...
    99+
    2022-11-13
  • C语言指针教程示例详解
    目录指针内存指针类型指针运算二级指针指针数组指针 指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作...
    99+
    2022-11-13
  • 详细理解函C语言的函数栈帧
    目录一、函数栈帧的创建1.寄存器2.函数栈帧3.函数中调用函数二、函数栈帧的销毁总结一、函数栈帧的创建 1.寄存器 一般来说,计算机中的寄存器有六种 分别是:eax, ebx, e...
    99+
    2022-11-12
  • C语言进阶教程之函数指针详解
    目录一、函数指针1.概念1.2函数指针的使用方法1.3练习巩固1.4小结一下二、阅读两段有趣的代码1.( *(void( *)( ))0 )( )2.void (* signal(i...
    99+
    2022-11-13
  • C语言实现阶乘的示例详解
    目录前言1.阶乘实现1.1理论步骤1.2实践结果2.连续乘层相加实现2.1理论步骤2.2实践结果前言 在现实中,我们做数学题总会遇到阶乘问题,这在计算机中也不例外。 那我们应该怎么实...
    99+
    2022-11-13
  • c语言函数栈帧的创建和销毁过程详解
    目录1 相关知识介绍 1.1 寄存器1.2 函数栈帧概述2 栈帧创建与销毁过程1 相关知识介绍  1.1 寄存器 一般计算机内通用寄存器包括eax,ebx,ec...
    99+
    2022-11-12
  • C语言函数栈帧的创建与销毁详解
    目录前言一、函数栈帧是什么?1.寄存器2.ebp与esp二、函数栈帧的创建1.代码块2.调用堆栈3.esp与ebp如何维护栈帧总结 前言 大家在学习的时候一定有以下困惑: ...
    99+
    2022-11-13
  • C语言函数栈帧的创建和销毁详解
    目录写在前面Add函数的调用函数传参Add函数栈帧的创建Add函数栈帧的销毁main函数栈帧的销毁总结写在前面 我们知道,每一次函数调用都需要在栈区上为其开辟一块空间,这块空间就叫做...
    99+
    2022-11-13
  • Go 语言进阶单元测试示例详解
    目录前言测试单元测试规则示例assert覆盖率依赖Mock基准测试前言 本文从单元测试实践角度出发,提升对代码质量的意识。 本文内容主要包括:单元测试、Mock测试、基准测试。 测...
    99+
    2023-01-28
    Go 语言单元测试 Go 单元测试
  • C语言进阶教程之循环语句缺陷详析
    目录前言1 循环语句的三要素2 使用不同循环语句实现六种排列组合2.1 第一种排列(ABC)2.2 第二种排列(ACB)2.3 第三种排列(BCA)2.4 第四种排列(CBA)2.5...
    99+
    2022-11-12
  • Swift进阶教程Mirror反射示例详解
    目录元类型与.selfAnyObjectAnyClassAnytype(Of:)selfself在方法里面的作用Self引用Swift RuntimeMirrorMirror的基本用...
    99+
    2022-11-13
  • C语言编程大小端问题示例详解教程
    目录如何理解大小端大小端的基本概念大小端是如何影响数据的存取的今天想给大家分享的,是数据存储中的大小端问题,今天的分享主要分为三个部分,分别是如何理解大小端,大小端的基本概念以及大小...
    99+
    2022-11-12
  • C语言进阶教程之预处理
    目录一.代码运行是的两种环境二.翻译环境三.预定义符号四.#define1.define  定义宏2.带有副作用的宏参数五.#define定义宏 与函数对比六.预处理指令七...
    99+
    2023-02-10
    什么是预处理 c语言编译预处理命令 c语言预处理指令作用
  • C语言解决堆栈括号匹配问题示例详解
    目录首先构建栈调用匹配函数代码调用1.括号匹配问题就是当遇到{( [这些左括号的时 将括号字符入栈 2.当遇到右括号时判断栈顶元素是不是与左括号匹配如果匹配就出栈 如果不匹配就直接结...
    99+
    2022-11-12
  • C语言数据结构线性表教程示例详解
    目录线性表顺序表线性表 数据结构里我们时常看到什么什么表,线性表是最基本、最简单、也是最常用的一种数据结构,其他各种表的万恶之源就是这个线性表,他是个啥其实顾名思义: 一个线性表是n...
    99+
    2022-11-13
  • C语言超详细讲解函数栈帧的创建和销毁
    目录1、本节目标2、相关寄存器3、相关汇编指令4、什么是函数栈帧5、什么是调用堆栈6、函数栈帧的创建和销毁(1)、main函数栈帧的创建与初始化(2)、main函数的核心代码(3)、...
    99+
    2022-11-13
  • C语言 指针数组进阶详解
    目录指针与数组中的sizeof与strlensizeofstrlen数组名1、一维数组整型数组字符数组指针数组2、二维数组指针笔试题 笔试题1笔试题2笔试题3笔试题4笔试题...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作