当前位置:首页 > 单片机 > 单片机
[导读]栈是一种具有先入后出特性的数据结构,前面说过,这种特性常常用来帮住我们“原理返回”或者“保持原样”。试想,当我们第一次来到一个陌生的城市,走在陌生的街道上,寻找一个陌生的目标,最令

栈是一种具有先入后出特性的数据结构,前面说过,这种特性常常用来帮住我们“原理返回”或者“保持原样”。试想,当我们第一次来到一个陌生的城市,走在陌生的街道上,寻找一个陌生的目标,最令我们有安全感的莫过于仔细记录走过的每一个街道、穿过的每一个路口--这种安全感来源于潜意识里“万一找不到目的地就原路返回”的想法。记得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*/

...

}

当程序运行到断点1时,因为还没有发生任何函数调用(我们假设测试环境中没有使用到操作系统,因此不存在操作系统调用main函数的问题,也就是不存在将操作系统相关的内容压入栈中的问题),此时,栈是空的,如图13-10(a)所示。


程序继续运行,发生函数调用--FuncA(),并在其中遇到了断点A1。因为此时发生了函数的调用,结点main被压入栈中。此时只是一个结点,如图13-10(b)所示。程序运行到断点2,系统从函数FuncA()返回,因此,将结点main弹出,如图13-10(c)所示。


继续运行程序,直到再次遇到断点A1。此时,栈中有两个元素,从栈顶向下分别是FuncB、main。这说明,在此之前,发生了两次调用:首先是main调用了FuncB,紧接着在FuncB中调用了FuncA,如图13-11(a)所示。当我们遇到断点B1时,程序已经从FuncA中返回,因此弹出了栈顶元素FuncA,如图13-11(b)所示。经过断点3时,结点main也被弹出,栈再次成为空栈,如图13-11(c)所示。


当程序第三次执行到断点A1时,由于发生了三次函数调用,因此,栈中有三个结点FuncB,FuncA和main,如图13-11(d)所示。再次经过断点B1时,程序从函数FuncA中返回,因此弹出了栈顶元素FuncB,如图13-11(e)所示。程序继续执行,从函数FuncB中返回遇到断点C1时,结点FuncC被弹出,如图13-11(f)所示。


从断点C1向后执行,调用函数FuncA第四次遇到断点A1,结点FuncA再次被压入栈中,如图13-12(a)所示。程序从函数FuncA返回,经过断点C2 时,弹出栈顶指针FuncA,如图13-12(b)所示。当我们遇到断点4时,程序已经回归到主函数main(),栈中最后一个结点被弹出,称为空栈,如图13-12(c)所示。


通过上面的模拟,我们展示了C编译器利用栈实现函数嵌套条用的原理。详细情形大家可以参考编译原理的相关内容,这里就不再深入。前面,我们知道,没当发生一次函数调用,编译器都要保存当前的相关信息。这一信息至少包括两大部分:其一,用于描述程序从函数调用中返回时,返回到哪个函数位置;另一部分,用于描述与当前函数有关的一些局部信息(比方说局部变量)。在ICC中,编译器将两个独立开来,分别使用两个栈来保存。保存函数返回地址(也就是第一部分)的栈被称为硬件栈(Hardware Stack 或者 Resturn Stack)。保存当前函数局部相关信息的栈,我们称之为软件堆栈(Software Stack)。


将原来完整的结点信息一分为二,究竟是出于怎样的考虑呢?我们知道,单片机的内存容量有限(ATMeag48的SRAM仅有512个字节),不可能允许无限制的函数嵌套,必须对栈的尺寸加以限定。在正常情况下,一个结点中包含的信息总是包含定长和不定长两个部分。其中,表示函数返回地址的部分由于指针长度固定为2个字节,因此属于定长部分。将其单独作为一个结点保存在硬件堆栈中,便于规定函数允许嵌套的最大深度(例如,当我们设定HW Stack的最大尺寸是16时,就表示所允许的函数嵌套深度最大为8层)。出去函数返回地址,我们将其余的变长信息统一放在软件堆栈中,而这一部分的尺寸我们是无法预计的--栈究竟需要多大空间,完全取决于用户在函数中定义了多少局部信息(比方说局部变量)及函数嵌套了多少层,因此,我们总希望能给HW Stack提供尽可能大的空间。


出于以上考虑,ICC系统采用硬件栈和软件栈分开存储的方式。编译器要求硬件栈的大小必须在程序编译器前由用户给定(在ICC集成开发环境中,有Compile Option--Target选项卡的Return Stack Size选项卡来设定),如图13-13所示。硬件栈位于SRAM的高地址,采用向上生长的方式,大小直接受到从栈底地址开始至存储器顶端所剩余的空间限制。这一空间大小恰好等于Return Stack所设置的数值。软件栈与硬件栈背靠背存放,采取向下生长的方式,虽然其大小受到诸多因素的共同影响,但最大尺寸在编译完成后也是确定的,如图13-14所示。


考虑到存储器的大小的限制,我们在编写单片机的程序时,一定要精打细算。一个程序,当系统中使用了大量的中断资源,并且允许了中断嵌套的存在,那么在极端的情况下,中断处理程序就很容易发生嵌套现象。此时适当扩大硬件堆栈的大小,支持较大的函数嵌套深度,往往能解决很多莫名其妙的跑飞问题。与拥有丰富存储器资源时的状况不同,由于局部变量在函数发生嵌套时,都要占用软件堆栈空间,因此大量使用使用局部变量或者使用了占用空间颇为可观的局部数组(也包括体积巨大的结构体),在嵌套深度较大时,都有可能造成向下生长的软件堆栈侵入其他存储区域(详细情形阅读ICC的帮助文档),导致某些变量意外修改、程序跑飞等现象。解决这一问题的方法其实很简单,在某些局部变量占用空间较大的情况下,将其通过关键static声明为静态变量--这样即保证了变量的局限性,又避免了将这些内容压入软件栈中(静态局部变量在存储时和全局变量没有本质区别,采用的都是 静态分配),只不过每次使用这些变量之前都要记得补充必要的初始化代码。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭