C解析之五函数内幕
前言:关于函数,你不知到的那些事。
C语言程序由多个函数组成,所有函数具有平行性,这意味着函数内部不能再定义函数。函数带来一大串问题,全局变量与局部变量是什么?它们的作用域与生存期有何不同?实际参数与形式参数又有何不同?为什么形式参数只有在被调用时才分配内存?返回值如何传递......在很多书上都可以找到答案,但...问题是,很少有书给予了让人满意的解释。
接下来尝试解开这些问题的原由,请看示例程序:
1.main()调用前:
1.1压栈保存现场: main将寄存器数据与机器状态压栈保存,当调用结束后,把这些压入栈的数据弹出就可以恢复main的运行,如图main指示的区域。
1.2参数入栈: 参数列表(m,n)按从左到右的顺序压入栈。
1.3返回地址入栈: 这是main()函数的下一条指令的地址,保存这个地址返回main后才知道该执行main的那条指令。
2.Swap()被调用后:
2.1建立自己的堆栈:Swap()在如图Swap指示的区域建立自己的堆栈,这是每个函数运行的基础,局部变量等空间开辟均基于堆栈。
2.2建立局部变量: Swap()在自己的栈上建立局部变量(包括函数定义的形式参数),栈在Swap指示的区域。局部变量存储位置问题,可参考【C解析之三】C语言的内存分配。
2.3 Swap开始执行指令:函数运行的条件-堆栈建立完成后,Swap开始执行代码,完成其任务。
2.4参数的访问
: Swap通过基地址+偏移量访问参数,如基地址+8是第一个参数m,基地址+12是第二个参数n的地址,并将其值赋给建立的局部变量a,b。
3.Swap()执行完后:
3.1清理堆栈: Swap的任务已经完成,维持它运行的堆栈就没有存在的理由。
3.2返回值 : 如果有返回值,一般是将返回值放在寄存器中,main冲寄存器中获得返回值。
4.main()恢复:
4.1返回地址 : 这条指令地址取出放入指令寄存器(处理器下一条处理的指令放在这个寄存器内)。
4.2弹栈恢复现场 :这个过程与1.1过程相反,恢复main调用前的环境。
4.3获取返回值 :如果有,一般到相应的寄存器内读取。
至此,函数调用过程结束。现在分析这个过程,以期望可以找到问题的答案:
1.全局变量与局部变量:全局变量不依赖任何函数,至始至终都存在,存储于静态区。2.1-2.1到3.1可以发现,局部变量时在函数被调用后才开始分配空间,并最终随函数一起消亡。
2.生存期: 全局变量显然在整个程序过程都一直存在,而局部变量生于函数调用时,死于函数调用结束。
3.实际参数与形式参数:通过1.2与1.2-1.4清楚的表明,形式参数是函数的局部变量,创建于函数调用时,并被参数赋值。赋值则意味着在被调用函数内的操作,将不会影响到实参m,n的值,Swap并不具有m,n互换的功能。(读者可以试试,实际上Swap(int
&a,int &b)这样定义才具有交换的功能)。
4.参数的传递 :参数的传递是通过地址偏移量完成,其中更多的细节参考C调用约定。
5.返回值: 一般情况下,返回值通过寄存器传递,更多细节参考C调用约定。
catalan数。大数与小数的相乘和相除(hdu1134),布布扣,bubuko.com
catalan数。大数与小数的相乘和相除(hdu1134)
原文:http://blog.csdn.net/fei____fei/article/details/21327925