首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

软件堆栈和硬件堆栈

软件堆栈和硬件堆栈

栈是一种具有先入后出特性的数据结构,前面说过,这种特性常常用来帮住我们“原理返回”或者“保持原样”。试想,当我们第一次来到一个陌生的城市,走在陌生的街道上,寻找一个陌生的目标,最令我们有安全感的莫过于仔细记录走过的每一个街道、穿过的每一个路口--这种安全感来源于潜意识里“万一找不到目的地就原路返回”的想法。记得20世纪90年代,有一首家喻户晓的流行歌曲《星星点灯》中曾这样唱到“星星点灯...为迷失的孩子,照亮来时的路”。


“找到来时的路”这种想法是人们基本的求生本能,对有人类编写的C语言编译器来说,也是这样--面对一层一层复杂嵌套关系的函数调用,编译器总是试图记录下我们调用的过程,以便“找回回去的路”。栈就在这种场合中,得到了广泛的应用。


C语言支持函数的调用,这完全得益于栈式分配策略的使用。所谓栈式分配,抛去复杂的技术细节,简单说来,就是将函数内部使用的种种信息(例如,局部变量)在发生函数嵌套调用时,压入栈中“记录下所走过的路”。这样,当调用的函数运行结束需要返回时,编译器就能很容易从栈中找到“来时的路”。使用模拟的方法,我们来具体看看这一过程。


我们假设:一个函数中所有牵涉到的局部信息都被包含在一个与函数同名的接节点中。当我们在某一个函数中发生了对另外一个函数的调用,就将本函数的局部信息压入栈中--也就是将以该函数命名的结点压入栈中:当我们从某一函数中返回,就从栈中弹出一个结点。观察一段代码的函数调用情况,了解编译器如何借助来实现函数的嵌套调用。


//这是一段演示用的伪代码,包含了一些函数并设置了一些断点便于观察
//函数的细节已经省略,只保留了对其他函数的调用关系
//函数A
void FuncA(void)
{
//没有任何针对其他函数的嵌套调用
/*断点A1*/
}
//函数B
void FuncB(void)
{
...
FuncA();//调用了函数A
/*断点B1*/
...
}
//函数C
void FuncC(void)
{
...
FuncB();//调用了函数B
/*断点C1*/
FuncA();//调用了函数A
/*断点C2*/
...
}
//主函数
void main(void)
{
...
/*在这里,我们设置一个程序断点,称为断点1*/
FuncA();
/*断点2*/
FuncB();
/*断点3*/
FuncC()
/*断点4*/
...
}
返回列表