C51变量的存储

发布者:温馨生活最新更新时间:2016-12-15 来源: eefocus关键字:C51  变量  存储 手机看文章 扫描二维码
随时随地手机看文章

一、全局变量和局部变量

全局变量和局部变量的区别在于作用域的不同。此外还有静态全局变量和静态局部变量。

全局变量作用域为全局,在一个源文件中定义,其他的源文件也可以应用。在其他的源文件中使用extern加以声明;

静态全局变量作用域为该源文件,只作用在声明它的源文件中,通过static声明,这样即使在其他的源文件中有相同名称的变量也不相同;

局部变量作用域为函数内部。当函数被调用时,为其分配空间,函数调用完成后收回内存,销毁变量;

局部静态变量作用域为局部,只被初始化一次,但是在后面它一直存在。即使函数调用完成后也一直存在。

全局变量和局部变量都是要分配内存的,它们的区别只是在于作用域不同。

在C中,全局变量、静态全局变量及静态局部变量都在静态存储区,由于这些变量的生存周期较长,占有较多的内存但是由于已经分配好了内存,因此速度较快,而局部变量则在栈中分配空间。在KeilC51中这是不同的。

二、C51中的全局变量和局部变量

在51中程序ROM和数据RAM是严格分开的,特殊功能寄存器与片内数据存储器统一编址。这与其他一般的微机不同。51中内部的RAM有256字节,外部可寻址64KB,对于256字节,其中前128字节(00-7FH)又分为三部分:通用寄存器组、可位寻址区、用户RAM区;高128字节(7F-FF)为SFR。上电复位后堆栈指针指向07H,在通用寄存器区,此时对战区占用1,2,3组寄存器,但是用户可自行将sp设置在30-7F。

C51编译器通过将变量定义为不同的类型,来区分不同的存储区,常用的变量类型有:

data:片内RAM的低128字节

bdata:可位寻址的片内RAM

以上两种类型可以快速的存取数据,常用来放临时性的传递变量或使用频率较高的变量。

idata:整个片内RAM。

xdata:片外存储区(64KB),由于在对片外存储区操作时,需要先将数据移到片内,进行处理后再存储到片外,因此常用来存放不常用的变量,或收集待处理的数据,或存放要被发往另一台计算机的数据。

pdata:属于xdata类型,由于它的高字节保存在P2口中,只能寻址256字节。

code:ROM内,数据不会丢失。

此外,C51还有三种存储模式:SMALL, COMPACT, LARGE

SMALL模式下,如果不做特别说明,参数及局部变量默认为data型,放在片内RAM128字节内,访问迅速。由于内部的RAM有限,如果变量过多,会导致频繁的使用寄存器,而使代码变的冗长。此时栈也在片内的RAM,栈长很关键,因为栈长依赖于不同函数的嵌套层数。

COMPACT:不做特别说明,参数及局部变量默认为pdata,栈空间在内部RAM。

LARGE:参数及局部变量默认为xdata,使用DPTR来寻址。访问效率低,此外这种数据指针不能对称操作。

全局变量会根据定义的类型或者存储的模式分配在相应的存储区内,有固定的地址,如果全局变量过多则会导致占用太多内存,处理速度变慢。

三、共享和覆盖

由于51的存储区有限,因此变有了覆盖和共享的概念。

共享:有共享变量和共享函数,共享是针对全局变量或静态变量而言的,对全局变量定义后就对其分配了内存,在任何函数或者程序中都可以共享该变量的内存,在其他的文件中也可以通过声明extern来实现共享。共享函数也是类同。

覆盖:如果一个程序不再被调用,也不由其他的程序调用,在其他的程序运行之前程序也不在运行,那么这个程序的变量可以放在与其他的程序完全相同的RAM空间,这就是覆盖。

对于函数之间的覆盖在Keil中有一段描述:

The system the linker uses to determine which function arguments (or parameters) and variables may be overlaid is quite sophisticated. It begins when the compiler generates the object code for a function.

The compiler stores all function parameters and local variables in overlayable bit, data, pdata, or xdata segments. The segment names generated by the compiler for Parameters and Local Variables are well-defined. They are used by the compiler to access parameters and local variables.

As the linker resolves references between functions, it builds a call tree based on where those references appear. For instance, if function_a callsfunction_b, the compiler inserts a reference to function_b in the object code generated for function_a. When the linker resolves this reference, it inserts the address of function_b and adds a call from function_a to function_b in the call tree.

The local variables and parameters of function_a are overlaid with the variables and parameters of function_b only under the following conditions:

  1. No call references of any kind may exist between function_a and function_b. This includes direct calls between A and B as well as calls from other functions on the A branch to B and calls from functions on the B branch to A.

  2. The functions A and B may be invoked by only one program event or root: either the main root or an interrupt but not both. It is impossible to overlay variables and parameters if a function is called by an interrupt and the main program or by two interrupts.

  3. The segment definitions of functions A and B must conform to the rules for segment names described in the compiler manual.

 

在函数中定义的动态局部变量可以被覆盖,一个函数说明的变量在下一次进入函数时不同,即函数调用时会发生变化(函数调用时才为局部变量分配空间,因此每次调用分配的地址可能不同)。有一些编译器通常把局部变量放在堆栈上,这样运行起来位置不固定,栈操作不方便,而在51的编译器中则监视函数调用的嵌套顺序,把几个函数的变量放在同样固定的位置。在51编译器中连接器会搜索所有函数中局部变量占用存储区间最多的函数,然后已这个函数的局部变量的占用的空间的多少开辟一片空间,其他函数的局部变量也放在该空间中,同时实现了变量的覆盖(无相互调用)与地址的共享。例如函数A占10个字节,函数B占20个字节,函数C占15个字节,如果它们之间没有相互调用则仅需20个字节就可以满足45个字节的变量需要。

C51中根据变量定义是的数据类型在相应的存储区内为变量分配内存,在内部整个RAM区中,先为定义在该端的全局变量分配地址,然后是程序中所有函数的参数和局部变量的覆盖区(内部RAM存取迅速)。以上两部分内存都是上面所说的C中的静态存储区(段)。接下来就是系统的堆栈,栈底有?STACK自动生成,栈顶在0xFF。

正是由于所有函数的参数和局部变量的共享一个覆盖区,函数没有相互的调用时,在执行一个函数时,会将另一个函数的变量的存储区覆盖。如果函数有调用,那么不会覆盖原来函数的局部变量的区间,但如果函数的嵌套(递归)层数太多,所有的变量的内存大于了覆盖区时,一个函数的内部的变量可能会被新调用的函数冲掉,再返回该函数时,无法找到相应变量的内存,也就无法找到该变量的值。通过声明为可重入函数,让参数和变量放在堆栈中。

对于覆盖,大多人认为是为了节省内存,但网上有另一种说法,个人觉得很有道理,引用如下:

一般的C编译器(或者更确切点地说:基于一般的处理器上的C编译器),其函数的局部变量是存放于堆栈中的,而C51是存放于一个可覆盖的(数据)段中的.

  至于C51这样做的原因,不是象有些人说的那样,为了节约内存.事实上,这样做根本节约不了内存.理由如下:

  1) 如果一个函数func1调用另一个函数func2,那么func1,func2的局部变量根本就不能是同一块内存.C51还是要为他们分配不同的RAM.这跟使用堆栈相比,节约不了内存.

  2) 如果func1,func2不是在一个调用链上,那么C51可以通过覆盖分析,让它们的局部变量共享相同的内存地址.但这样也不会比使用堆栈节约内存.因为既然它们是在不同的调用链上,那么当其中一个函数运行时,那么另外一个函数必然不在其生命期内,它所占用的堆栈也已释放,归还给系统.

  真实的原因(C51使用覆盖段作为局部变量的存放地的原因)是:

  51的指令系统没有一个有效的相对寻址(变址寻址)的指令,这使得使用堆栈作为变量的代价太过昂贵.

  使用堆栈存放变量的一般做法是:

  进入函数时,保留一段堆栈空间,作为变量的存放空间,用一个可作为基址寻址的寄存器指向这个空间,通过加上一个偏移量,就可以访问不同的变量了.

  例如: MOV EAX, [EBP + 14];X86指令

  LDR R0, [R12, #14];ARM指令

  都可以很好的解决这个问题.

  但51缺少这样的指令.

  *其实,51中还是有2个可变址寻址的指令的,但不适合访问堆栈的局部变量这样的场合.

  MOVC A, @A+DPTR

  MOVC A, @A+PC

  所以,C51有个特别的关键字: reentrant 用来解决函数重入的问题。


关键字:C51  变量  存储 引用地址:C51变量的存储

上一篇:C51单片机内存优化
下一篇:Keil C51处理可重入函数问题的探讨

推荐阅读最新更新时间:2024-03-16 15:25

C51串口中断---接收和发送
C51单片机(STC11L32/48/60XE)的串口中断处理函数,如果在使能串口中断后,有接收或者发送数据时,就会设置中断标志位,进而处理中断函数。 接收数据,设置RI=1,处理完中断函数后,再设置RI=0。同理,发送数据,设置TI=1,处理完中断函数后,再设置TI=0。
[单片机]
一种数字化语音存储与回放系统的设计
系统设计 总体设计 系统主要由语音处理前向通道、A/D转换、单片机控制兼数据处理、D/A转换、键盘显示模块及后向处理通道组成,单片机构成系统的控制中心,用来进行控制功能选择和结果显示。CPLD内集成373、138和分频器。通过前级放大,将微弱的电信号放大到2.5v,中间由射极跟随器进行隔离,再通过300Hz~3.4kHz的带通滤波器滤除50Hz的市电影响和高频噪声。ADC0809的参考电压选为+5V,其采集的电压信号范围是0~+5V。而语音信号是双极性的,可正可负(滤波器输出信号幅值约为土2.5V),因此,有必要加一直流偏置电压(约为+2.5V),使语音信号变为单极性信号(0~+5V),保证ADC0809采样有效,同时也保证
[手机便携]
相变存储器速度新极限
  随着数字全球化,爆炸式增长的信息对数据的存储与传输提出了极大的挑战,而且目前商用计算体系架构内各存储部件,即缓存(SRAM)、内存( DRAM )和闪存(NAND Flash)之间性能差距日益加大,其间的数据交换效率也已成为了电子设备发展的瓶颈。因此研发具备存储密度大、读写速度快、能耗低、非易失(即断电后数据不丢失)等特点的新式通用式存储介质势在必行。下面就随网络通信小编一起来了解一下相关内容吧。   0.7纳秒!相变存储器速度新极限   近日,美国Science杂志发表了西安交通大学与上海微系统与信息技术研究所的合作论文——《Reducing the stochasticity of crystal nucleatio
[网络通信]
基于P89C61x2/ISP1581的USB接口电路的设计
本文主要针对传统仪器的并行接口设计了一种基于单片机的接口电路。 主要芯片介绍 本设计采用控制芯片P89C61x2和接口芯片ISP1581实现USB接口电路的设计。 P89C61x2包含1024B RAM、64KB Flash存储器、32个I/O口、3个16位定位/计数器、6个中断源-4个中断优先级-嵌套的中断结构、1个增强型UART、片内振荡器和时钟电路。此外,器件的静态设计使其具有非常宽的频率范围,可选择1MHz~12MHz的晶体振荡器。具有两个软件可选的节电模式-空闲模式和掉电模式。 USB接口芯片ISP1581是一种价格低、功能强的USB接口器件,符合USB2.0规范,并为基于微控制器或微处理器的系统提供了高速USB通信能
[应用]
C8051F02X外部存储器接口和I/O端口配置
摘要:介绍美国Cygnal公司生产的C8051F02X系列单片机的外部存储器接口、I/O端口配置方法和有关注意的问题;在此基础上列举两个关于EMIF、I/O的配置应用。 关键词:C8051F02X EMIF I/O 交叉开关 美国Cygnal公司C8051F02X系列单片机是集成在一起芯片上的混合信号系统级单片机。该单片机具有32/64位数字I/O端口(引脚)、25MIPS高速流水线式8051微控制器内核、64KB在系统可编程Flash存储器、64KB地址的外部存储器接口、4352(4096+256)B片内RAM、各自独立的SPI、SMBUS/I2C和两个UART串行接口等特点。其最突出的优点就是,通过设置交叉开关寄存器控制
[应用]
从此决裂,美光将与英特尔在3D XPoint存储芯片市场上大打出手?
   英特尔 已经推出了几款3D XPoint产品,但是到目前为止, 美光 科技还没有什么动作。下面就随手机便携小编一起来了解一下相关内容吧。   尽管目前来看, 英特尔 的芯片主要面向个人电脑,而 美光 科技的芯片主要面向服务器,但是 英特尔 技术路线图进取十足,意味着不久的将来我们就能看到这两家公司产品的短兵交接。    美光 在服务器市场上迟迟未能推出3D XPoint产品,英特尔可能会捷足先登。   在最近这个季度的DRAM和NAND市场上,美光在DRAM产品的出货量和运营利润率方面超过了英特尔。   2005年,英特尔和美光成立了一家合资公司英特尔-美光闪存科技(IMFT),旨在共同制造NAND闪存,第一款产品就是72
[手机便携]
基于C51单片机的校园自助导览仪设计
摘要:在分析MP3标准算法的基础上,基于C51单片机实现MP3的编解码,并对MP3编码进行了多方面的优化;在单片机上的MP3算法中加入无线功能,设计成为一种校园自助导览仪。经野外测试,效果良好。 关键词:MP3编解码;无线模块;自助导览 引言 MP3是MPEG-I的音频标准第三层压缩模式。虽然算法比较复杂,但压缩比最大在低码率条件下基本能达到CD的音质效果。其压缩比例高、音质失真小的特点使之成为用于当前PC、网络、PDA等最为流行的音频格式。在嵌入式系统中实现MP3音频编解码常见的有两种方案;一种是硬件解码(即通过专用的MP3解码硬件进行解码),其特点是可以实现较高的性能和较低的功耗,目前大多数商用MP3都采用这种方案;另外一
[单片机]
基于<font color='red'>C51</font>单片机的校园自助导览仪设计
国产铁电存储器PB85RS2MC用于汽车仪表盘,兼容富士通
汽车系统的设计变得越来越复杂,因为要不断的加入新的功能,如高级驾驶辅助,图形仪表,车身控制和车辆信息娱乐系统。为了确保可靠、安全的操作,每个子系统都需要使用特定的非易失性存储器,方便在复位操作和电源切换期间存储信息。非易失性存储器用于存储可执行代码或常量数据、校准数据、安全性能和防护安全相关信息等重要数据,来作为将来的检索用途。 仪表盘系统框图 1、汽车仪表盘对存储器的要求 汽车是仪表盘系统是以数字形式在图形显示器上显示速度、转速、燃油油位和发动机温度等重要信息,或者使用步进电机控制的模拟形式显示。此外,仪表盘系统还可以显示电池警告、温度警告、低油压警告、制动警告、安全带状态标识、低胎压标识、门锁标识、车头灯标识、换档指示
[嵌入式]
国产铁电<font color='red'>存储</font>器PB85RS2MC用于汽车仪表盘,兼容富士通
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved