zoukankan      html  css  js  c++  java
  • 栈论 : 递归与栈式访问,如何用栈实现所有递归操作(函数调用底层篇)

    重大错误说明 : 栈顶的指针始终是指向最后一个入栈元素的位置的,不是最后一个入栈元素的位置上面!请读者留意 (PS : 后来又看了一下,好像也不是什么大问题...)

    上一篇 :

    栈论 : 递归与栈式访问,如何用栈实现所有递归操作(基础知识篇)

    2.函数调用底层篇(了解递归调用的硬件实现)

    一开始,main函数没有调用add之前他的栈帧如下图,当然,下面只是简略介绍,实际上内存布局比下面更复杂(省略了寄存器等)。

     

     当要调用add函数的时候main 将 自己的变量拷贝后压入栈中,我们称之为“形参”

    上图中变量c 和变量d的拷贝就是所谓的”形参“

     接下来将main函数的ebp地址压入栈中保存,以便add函数调用完之后恢复main在内存中的栈帧

    接着 就是重要的环节,add函数的栈帧创建,add函数的栈帧创建在add函数自己的操作里。

    没想到吧?add函数的栈帧是add函数自己创建的。一般的思维都是父对象为子对象创建空间,再让子对象自己发挥,可能这是比较袒护孩子的行为吧,你看函数调用却是让自己的孩子去开创天地,值得学习。(当然 这是win10下汇编的得出的结果,可能不同系统不一样)

    add函数本身操作 :

    1.将esp 的值赋给ebp,这里的ebp就是add函数自己栈帧的栈底了。

    2.让esp = esp - X ; X是一个位移量,表示esp要上移,esp上移的这个位移量差不多是add函数栈帧的大小。(还有一些寄存器之类的会占用空间,忽略不计)

    如图:

    这时候的栈应该是这样的

     

     接下来,涉及到最重要环节!栈帧之间的通信

    add函数的内部操作是 两个数相加,这两个数是形参,难道在add函数的栈帧中要访问在main函数栈帧中的形参吗?没错,就是直接访问。

    我们来看看a + b 的汇编过程

    对汇编不了解的同学可以先把 eax理解成一个变量,这个变量不在内存中(当然也就不在我们的栈区中)。mov是放进去的意思,理解把逗号右边的值放到(赋给)左边变量上(eax)去。 add是把逗号左右两边的数加起来,放到左边去。

    我们发现,a + b 无非是把 ebp + 8, ebp + 12(十六进制数0Ch的十进制数)读取到的值加起来并且放到eax变量里而已。

    而从 ebp + 8 和 ebp + 12 读取到的正好是main函数栈帧中的形参

    栈帧通信总结1.

    子函数直接调用父函数栈帧内的形成,访问父函数

    这是子向父索求信息,那么父向子索取信息呢?聪明的你可能已经猜到了,返回值!

    子函数返回过程:

    子函数完成之后,子函数的栈帧会被废弃掉

    上面大圈里的小圈,两句汇编就是把栈顶和栈底移动回原来的main栈帧处。

    在我们刚刚看到的a+b之后,子函数已经没什么大动作了,也就是说我们操作完之后的数是放在eax里的。

    父函数就是通过访问子函数结束后遗留在eax中的数来和子函数通信,也就是说,eax里的是子函数的返回值!

    从汇编也可以看到main在调用完add函数之后,为e赋值的时候直接访问了eax;

    add    esp,8

    这句还是要好好说一说的,子函数返回之后esp还在形参的上面,既然子函数完成了,形参也没必要存在,于是需要把他们废弃掉,废弃的方法是把他们移除esp和ebp之间,也就是让esp下降就好了。

    栈帧通信总结2.

    父函数直接访子函数在EAX中遗留的返回值

     

    综上,我们得出以下几点结论。

    1.子函数直接调用父函数栈帧内的形成,访问父函数

    2.父函数直接访子函数在EAX中遗留的返回值

    3.父函数调用子函数,子函数创建栈帧,子函数完成后子函数的栈帧销毁

    下一篇 :

    栈论 : 递归与栈式访问,如何用栈实现所有递归操作(幼儿园题目篇)

    护眼绿:

    没人看的结语:

    首先很感谢你看到这里,辛苦了。

    文章中某些地方可能不正确或不准确,代码也可能不够高效可读,希望读者能够帮忙指正,共同学习进步。

  • 相关阅读:
    归并排序
    汉诺塔系列问题: 汉诺塔II、汉诺塔III、汉诺塔IV、汉诺塔V、汉诺塔VI、汉诺塔VII
    Uncle Tom's Inherited Land
    汉诺塔III
    汉诺塔X
    Frosh Week
    hdu 1007最近点对问题
    POJ1579:Function Run Fun
    Hdu1163 Eddy's digitai Roots(九余数定理)
    放苹果问题
  • 原文地址:https://www.cnblogs.com/lqlqlq/p/11790435.html
Copyright © 2011-2022 走看看