分享

关于变量与存储空间的解惑

 hunancjz 2010-01-03
关于变量与存储空间的解惑!(keil中) 收藏
注意 keil 中带有 reentrant  关键字的函数是不同于这里将要说的东西(如 void myFunc(void) reentrant { } )
//在keil 中的compact (变量被定义在pdata中) 模式不能被定义

void main (void)
{
 int k[129];
}
在keil 中 有data 、idata 、pdata 、xdata 这几种对变量在内存中规定(后面将说到code、bdata、sfr、16sfr、bit、sbit)
//在C51的帮助中都有
unsigned char data variable;      //变量的地址在RAM上(最大为128 bytes)
unsigned char idata variable;   //变量的地址在RAM上(最大为256 bytes)
unsigned char pdata variable;   //变量的地址在外部扩展RAM上(256 bytes 每页)
unsigned char xdata variable;   //变量的地址在外部扩展RAM上(最大为64K bytes)
在编译时分配地址给变量,在生成二进制代码时把变量写成对应的地址,在程序写好后,内存就已经分配好, 
    13: void main (void)
    14: {
    15:         int s[32];
    16:         s[0] = 0x11;
C:0x0003    750800   MOV      0x08,#0x00            //0x08为s【0】的地址,在Hex文件中已不存在s【】这个概念
C:0x0006    750911   MOV      0x09,#0x11
    17:         s[9] = 0x99;
C:0x0009    751A00   MOV      0x1A,#0x00
C:0x000C    751B99   MOV      0x1B,#SBUF(0x99)
    18: }
C:0x000F    22       RET     
在没有操作系统的支持时,变量的定义都是一次性的,没有谁来回收过期的内存单元。一个函数中定义了,就再也不能在另一个函数中使用这个
地址,除非是全局的。这也引出了一种使用内存的方法(全部定义成全局的,不使用局部变量,不使用参数);

C:0x0000    02002B   LJMP     C:002B
     6: void main (void)
     7: {
     8:         int data d[20];
     9:         int idata id[39];
    10:         int pdata pd[128];
    11:         int xdata xd[32640];
    12:         d[0] = 0x11;      ;mov 直接寻址
C:0x0003    750800   MOV      0x08,#0x00
C:0x0006    750911   MOV      0x09,#0x11  
    13:         id[38] = 0x22;      ;mov 间接寻址
C:0x0009    787C     MOV      R0,#0x7C
C:0x000B    7600     MOV      @R0,#0x00   
C:0x000D    08       INC      R0
C:0x000E    7622     MOV      @R0,#0x22
    14:         pd[0] = 0x33;      ;movx 八位地址@R0  间接寻址
C:0x0010    7800     MOV      R0,#0x00
C:0x0012    E4       CLR      A
C:0x0013    F2       MOVX     @R0,A   
C:0x0014    08       INC      R0
C:0x0015    7433     MOV      A,#0x33
C:0x0017    F2       MOVX     @R0,A
    15:         xd[0] = 0x44;      ;movx 十六位地址@DPTR  间接寻址
C:0x0018    900100   MOV      DPTR,#0x0100
C:0x001B    E4       CLR      A
C:0x001C    F0       MOVX     @DPTR,A   
C:0x001D    A3       INC      DPTR
C:0x001E    7444     MOV      A,#0x44
C:0x0020    F0       MOVX     @DPTR,A
    16:         xd[32639] = 0x55;     ;movx 十六位地址@DPTR 间接寻址
C:0x0021    90FFFE   MOV      DPTR,#0xFFFE
C:0x0024    E4       CLR      A
C:0x0025    F0       MOVX     @DPTR,A   
C:0x0026    A3       INC      DPTR
C:0x0027    7455     MOV      A,#0x55
C:0x0029    F0       MOVX     @DPTR,A
    17: }

函数的参数与内存分配!【compact模式下】
//如果下面的代码中的 int pdata pd[124];  中124改为比他跟大的数,将通不过编译
//通过查看汇编代码可知:函数的参数也是要占内存空间的,这里通过R0~R7寄存器组来传递!
    13: void main (void)
    14: {
    15:         int data d[20];
    16:         int idata id[39];
    17:         int pdata pd[124];
    18:         int xdata xd[32640];
    19:         d[0] = 0x11;
    20:         id[38] = 0x22;
    21:         pd[0] = 0x33;
    22:         xd[0] = 0x44;
    23:         xd[32639] = 0x55;
    24: 
    25: }
C:0x002A    22       RET     
     3: void func1 (int s ,int k)     ;编译函数时参数的地址就固定了!
C:0x002B    7800     MOV      R0,#0x00    ;通过R0传递参数
C:0x002D    EE       MOV      A,R6
C:0x002E    F2       MOVX     @R0,A
C:0x002F    08       INC      R0
C:0x0030    EF       MOV      A,R7
C:0x0031    F2       MOVX     @R0,A
C:0x0032    08       INC      R0
C:0x0033    EC       MOV      A,R4
C:0x0034    F2       MOVX     @R0,A
C:0x0035    08       INC      R0
C:0x0036    ED       MOV      A,R5
C:0x0037    F2       MOVX     @R0,A
     4: {
     5:         
     6: }
     7: 
C:0x0038    22       RET     
     8: void func2 (int s ,int k)     ;编译函数时参数的地址就固定了!   
C:0x0039    7804     MOV      R0,#0x04    ;通过R0传递参数
C:0x003B    EE       MOV      A,R6
C:0x003C    F2       MOVX     @R0,A
C:0x003D    08       INC      R0
C:0x003E    EF       MOV      A,R7
C:0x003F    F2       MOVX     @R0,A
C:0x0040    08       INC      R0
C:0x0041    EC       MOV      A,R4
C:0x0042    F2       MOVX     @R0,A
C:0x0043    08       INC      R0
C:0x0044    ED       MOV      A,R5
C:0x0045    F2       MOVX     @R0,A
     9: {
//如果没有必要,变量还是定义成char吧!
/////////////////////////////////////////////////////

//字符串
     4: void main (void)
     5: {
     6:         char * data p = "ab";
C:0x0003    7BFF     MOV      R3,#0xFF
C:0x0005    7A00     MOV      R2,#0x00
C:0x0007    793F     MOV      R1,#0x3F
C:0x0009    8B08     MOV      0x08,R3
C:0x000B    8A09     MOV      0x09,R2
C:0x000D    890A     MOV      0x0A,R1
     7:         char data c = 'A';
C:0x000F    750B41   MOV      0x0B,#0x41
     8:         char data *x = &c;
C:0x0012    7F0B     MOV      R7,#0x0B
     9:         *x = 0x11;      
C:0x0014    A807     MOV      R0,0x07
C:0x0016    7611     MOV      @R0,#0x11
    10:         *p = 0x22;
C:0x0018    7422     MOV      A,#0x22
C:0x001A    120021   LCALL    C?CSTPTR(C:0021)
    11:         P0 = *x;
C:0x001D    E6       MOV      A,@R0
C:0x001E    F580     MOV      P0(0x80),A
    12: }
//从上面(还有实验结果)可以看出对字符串和其他变量的内存分配是不一样的!
//在VS2005中

void main (void)
{
 char *test = "xxxx";
 *test = 'A';  //异常
}
void main (void )
{
 char *p = "AAA";
 char bmp[10] = {'1','2','3','4','5','6','7','8','9','0'};
}
//初步分析,字符串被分配到了代码段中!是不能被访问的!
+  bmp 0x0012ff48 "12345678990" char [10]
+  p 0x00415650 "AAA" char *
//他们被分配的地址相差很多

///////////其他类型(Keil中)[可以参看C51的帮助]
code ///function的默认类型  char code ar[100]; 也可以把变量放到code段
bit //申明一个位变量
static bit done_flag = 0;    /* bit variable */
sfr、sfr16 特殊功能寄存器
sfr  PSW = 0xD0;
sfr16 T2 = 0xCC;     /* Timer 2: T2L 0CCh, T2H 0CDh */
sbit  特殊功能寄存器的位
sbit name = sfr-address ^ bit-position;
bdata //申明可位寻址的变量
//另外,指针所占的字节数也和data\xdata。。。有关
char data *p;  //p 占1 个字节
char xdata *p;  //p 占3 个字节
结束!
做一点补充:
 void func(void)
{
 char sz[100];
 sz[0] = 0x11;
 sz[1] = 0x22;
 sz[2] = 0x33;
}
void func2(void)
{
 char sz[100];
 sz[0] = 0x11;
 sz[1] = 0x22;
}
void main(void)
{
  func();
  func2();
}
func,和func2两个函数所占用的总内存不是200,而是100,C51处理局部变量不是通过堆栈来实现的,而是从固定地址开始分配变量0x08,0x09..... 这是我以前一直误会的地方,以前总以为C51没有用堆栈操作零时变量,所以每个函数中的变量都占用不同的地址,所以为了节省内存空间到处分配全局变量!!
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/by674868212/archive/2009/04/17/4088524.aspx

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多