注意 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没有用堆栈操作零时变量,所以每个函数中的变量都占用不同的地址,所以为了节省内存空间到处分配全局变量!!