堆和栈的作用及区别(学习)

简单的来说栈的作用就是
1.保存局部变量
2.传递参数
3.保存寄存器的值

在这里插入图片描述

栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈的特点是先入后出。符合这个特征的数据才可以在栈中存储。
在这里插入图片描述

在这里插入图片描述
在计算机系统中,栈则是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。在i386机器中,栈顶由称为esp的寄存器进行定位。压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。
栈在程序的运行中有着举足轻重的作用。最重要的是栈保存了一个函数调用时所需要的维护信息,这常常称之为堆栈帧或者活动记录。堆栈帧一般包含如下几方面的信息:
1.函数的返回地址和参数。
2.临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

栈的作用原理

一个函数设计里面,有2个问题:

1.参数传递
传递参数的目的,是为了代码可以重用,让一种方法可以应用到更多的场合,而不需要为N种情况写N套类似的代码。那用什么方法来做参数的传递?可以选择:

a.为了速度快,使用cpu的寄存器传递参数。这会碰到一个问题,cpu寄存器的数量是有限的,当函数内再想调用子函数的时候,再使用原有的cpu寄存器就会冲突了。想利用寄存器传参,就必须在调用子函数前把寄存器存储起来,然后当函数退出的时候再恢复。

b.利用某些ram(随机存取存储器)的区域来传递参数。这和上面a的情况几乎一样,当函数嵌套调用的时候,还是会出现冲突,依然面临要把原本数据保存到其他地方,再调用嵌套函数。并且保存到什么地方,也面临困难,无论临时存储到哪里,都会有上面传递参数一样的困境。

2.函数里面也有可能要使用到局部变量,而不能总是用全局变量。则局部变量存储到哪里合适,即不能让函数嵌套的时候有冲突,又要注重效率。

以上问题的解决办法,都可以利用栈的结构体来解决:
1)寄存器传参的冲突,可以把寄存器的值临时压入栈里面,非寄存器传参也可以压入到栈里面。
2)局部变量的使用也可以利用栈里面的内存空间,只需要移动下栈指针,腾出局部变量占用的空间。最后利用栈指针的偏移来完成存取。于是函数的这些参数和变量的存储演变成记住一个栈指针的地址,每次函数被调用的时候,都配套一个栈指针地址,即使循环嵌套调用函数,只要对应函数栈指针是不同的,也不会出现冲突。
3)利用栈,当函数不断调用的时候,不断的有参数局部变量入栈,栈里面会形成一个函数栈帧的结构,一个栈帧结构归属于一次函数的调用。栈的空间也是有限的,如果不限制的使用,就会出现典型的栈溢出的问题。有了栈帧的框架在,我们在分析问题的时候,如果能获取到当时的栈的内容,则有机会调查当时可能出现的问题。
在这里插入图片描述
然而栈存在的意义还不止这点,有了它的存在,才能构建出操作系统的多任务模式。

让我们看一下下面的一个main函数的调用实例,上面说的栈帧的情况依然,main函数调用A函数,调用B函数,再调用C函数,然后依次返回,试想当单cpu在main函数的框架运行的话,永远都在main函数厄结构里面(假设main函数是个无限循环结构),始终是在一个任务范围内,谈不上多任务。即使有另外一个任务在等待状态,如何在main函数里面跳转到另一个任务。显然在c语言的框架下,这无法实现,因为如果是函数调用关系,则本质上还是属于main函数的任务里面,不能算多任务切换。但需要注意到一个事实,此刻的main函数任务本身其实和它的栈绑定在一起了,无论是如何调用子函数,无论如何入栈退栈,栈指针都在本栈的范围内移动, 属于本任务的局部变量也和任务本身绑定了。

 main()

  ---->A()

      ----->B()

          ------>C()

          <-----C()

      <-----B()

   <----A()

main()

由此可以看出,一个任务状态可以利用如下信息来表征:
1.main函数体代码。
2.main的栈指针位置(即存储了局部变量等信息)。
3.当前cpu寄存器的信息。假如我们可以保存在这些信息,则完全可以强制让cpu去做别的事情,只是将来想继续执行main任务的时候,把上面的信息恢复就可以。
有了这样的先决条件,多任务就有了存在的基础。也可以看出栈存在的意义所在。在多任务模式下,当CPU认为有必要切换到别的任务上运行时,只需要保存好当前任务的状态,即上面说的三个内容。恢复另一个任务的状态,然后跳转到上次运行的位置,就可以恢复继续运行。可见每个任务都有自己的独立的栈空间。正是有了独立的栈空间,为了代码重用,不同的任务甚至可以混用任务的函数体本身,例如可以一个main函数有2个任务实例。有不同的栈空间,这完全可以实现。

至此之后的操作系统的框架也形成了,譬如任务在调用sleep()等待的时候,可以主动让出CPU给别的任务使用,或者分时操作系统任务在时间片用完是也会被迫的让出cpu。不论是哪种方法,只要想办法切换任务的上下文空间,切换栈即可。切换栈的实现并不能在c语言下完成,之前也说过c语言有意隐藏了栈的使用。所以在关键的上下文切换的地方,操作系统都需要用汇编代码来实现。

总的来说,栈的作用分为以下几点:
1)栈是每个函数架构的基础,实现了函数的重复利用。
2)问题发生的时候,可以利用栈来了解问题发生的情况。
3) 栈是构建出操作系统多任务模式的基础。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值