打印
[软件资料]

堆栈原理揭秘

[复制链接]
450|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
plsbackup|  楼主 | 2022-11-23 21:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. 什么是堆栈?
单片机应用中,堆栈是个特殊存储区,堆栈属于RAM空间的一部分,堆栈用于函数调用、中断切换时保存和恢复现场数据。堆栈中的物体具有一个特性:第一个放入堆栈中的物体总是被最后拿出来, 这个特性通常称为先进后出 (FILO—First-In/Last-Out)。 堆栈中定义了一些操作, 两个最重要的是PUSH和POP。 PUSH(入栈)操作:堆栈指针(SP)加1,然后在堆栈的顶部加入一 个元素。POP(出栈)操作相反,出栈则先将SP所指示的内部ram单元中内容送入直接地址寻址的单元中(目的位置),然后再将堆栈指针(SP)减1。这两种操作实现了数据项的插入和删除。

接下来博主尝试将百度百科试图传递的信息翻译为人话:
2. 为什么需要堆栈?
首先,为什么需要堆栈?真的是搞计算机的那帮宅男吃饱了撑的吗?
【编者注:必须不是!鲁迅曾经说过:“不想偷懒的程序员不是好程序员”,就算是吃撑了,程序员也只会是选择来知乎摸鱼】 其实每个看起来很玄乎的计算机概念,都是程序员为了以后能更方便的解决问题(偷懒)而提出的。
言归正传,堆栈其实是为了减少程序内存(RAM)占用的的问题而发明的。出于成本的考虑,单片机的内存容量一直都是非常有限的。而在单片机上电后,所有的变量又都需要被拷贝到内存中运行。为了解决这个矛盾,尽可能的节约代码在运行过程中变量所占用的内存空间,“堆栈”和“局部变量”这两个概念就被提了出来。其中“局部变量”从软件的角度指出了某些变量只需要在特定的时间段【生存期】存在于单片机的内存中即可满足程序正确运行的要求,而“堆栈”则从硬件的角度为程序员控制局部变量的生存期提供了便利。

3. 堆栈的功能是怎么实现的?
说的那么玄乎,堆栈和局部变量到底是怎么减少内存占用的呢?
3.1 软件的角度:
从功能实现的角度讲,函数实参和局部变量其实都可以用全局变量来实现。 但随之而来会有几个问题/缺点:
全局变量在程序执行的整个周期都存在,占用了大量的内存空间。有的变量明明就只被某个函数调用。既然这样,对于这种变量,我能不能在函数用的时候声明,调用完了就把它的内存空间释放掉,让给别的函数来用,这样不就大大提高了内存的利用率了吗,要知道单片机的RAM是很宝贵的。 想到这里,局部变量的概念就被发明了,即这些变量的生存周期只需要和对应的函数相同即可
【额外好处:由于局部变量在函数里面生成,所以函数copy到别的工程里面还能直接用,想想如果你把函数要用的变量声明在函数外,那你copy的时候还要特意去找,多麻烦】

3.2 硬件的角度:
想法非常好,当年的科学家也是这么想的,但是每次都手动的用汇编指令去创建,删除变量好麻烦!程序员也是人啊,于是为了摆脱繁琐的重复劳动,栈被发明了出来。栈并不是一个纯粹抽象的软件概念,而是由包括esp,ebp这些实际存在的堆栈寄存器来支撑的。
下面讲解这两个寄存器是如何将局部变量的创建和删除自动化起来,从而节约了程序员大量时间的:
Esp寄存器:存储栈顶地址
Ebp寄存器: 存储栈基地址
Esp到ebp地址之间被视为当前函数的栈空间,声明变量时,根据局部变量的大小,将堆栈寄存器esp的值下移,即可留出对应的空间用于存储该变量。而删除时,只需要将当前ebp的值赋给esp【即将栈顶指针直接压倒栈底】,即可自动将所有与该函数相关的局部变量清空,将所占用空间释放。一条指令,统一管理,统一释放,美滋滋!
最后总结一下,在相较于上古时期手动创建,删除全局变量来实现节约内存的无奈之举,通过堆栈实现局部变量的管理有一下优点:
  • 地址空间连续,没有碎片化,利用率高
  • 有专门的寄存器帮助,管理方便,push,pop一键删除
  • 生存周期短,函数没了就释放,所以同一RAM空间可以反复被不同函数使用
  • 因为有了局部变量的概念,就基本杜绝了其他函数误操作局部变量的可能,除非使用指针
  • 妈妈再也不用担心变量重名了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

3116

帖子

0

粉丝