单片机C语言指针意义浅析—Keil-C51

2019-04-15 18:13发布

通常认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上,甚至认为指针是C语言的灵魂。这里说通常,是广义上的,因为随着编程语言的发展,指针也饱受争议,并不是所有人都承认指针的“强大”和“优点”。在单片机领域,指针同样有着应用,本章节针对Keil C-51环境下的指针意义做简要分析。



1     指针与变量
指针是一个变量,它与其他变量一样,都是RAM中的一个区域,且都可以被赋值,如程序①所示。
#include "REG52.H"        
unsigned int j;
unsigned char *p;
void main()
{
         while(1)
         {
                   j=0xabcd;
                   p=0xaa;
         }
}
Debug Session模式下,将鼠标指针移到到变量“j”“p”位置,可以显示变量的物理地址,如图1-1、1-2所示。 






图中箭头所指处即为变量在RAM中的“首地址”,为什么是“首地址”呢?变量根据类型可分为8位(单字节)、16位(双字节),程序中变量“j”是无符号整型,所占物理空间应为2字节,而在8位单片机中,RAM的一个存储单元大小是8位,即1字节,因此需2个存储单元才满足变量“j”长度。所以实际上变量“j”的物理地址为“08H”“09H”。同理,“pD:0x0A)”即变量“p”的首地址为“0AH”。
下面通过单步执行程序来观察RAM内的数据变化,打开两个Memory Windows窗口,在Keil软件下方显示为Memory1Memory2,在两个窗口中,分别做如图2-1、2-2所示的设置。






两个Address填写的内容分别是:D:0x08D:0x0A,即量“j”和变量“p”的首地址,输入后回车,便可监视RAM中该地址下的数据。设置好后,准备调试。

Debug Session模式中,箭头所指处即为即将执行的语句,单击“Step”功能按钮(或按F11键),让程序运行,如图3所示。

第一次单击“Step”按钮后,Memory1窗口内数据如图4所示。

由调试结果可知,08H数据由00H变为ABH09H数据由00H变为CDH,出现这种变化是因为执行了语句j=0xabcd;08H为变量“j”高八位,存储“AB”,09H为变量“j”低八位,存储“CD”。
第二次单击“Step”按钮,执行语句:p=0xaa;此时需观察Memory2窗口内数据,如图5所示。

由调试结果可知,0CH处值由00变为“AAH”,程序相吻合。这里需要注意,在Keil C-51编译环境下,指针变量,不管长度是单字节或是双字节,指针变量所占字节数为3字节。故此处“AAH”不是存储在0AH而存储在0CH0A+2)地址中。
综上所述,指针实际上是变量,都是映射到RAM中的一段存储空间,区别是,指针占用3字节,而其他变量可根据需要设定其所占RAM1字节(char)、2字节(int)、4字节(long)。

2       指针作用
指针的作用是什么呢?先来看下面的程序:
程序②
#include "REG52.H"         
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char codetab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80}; 
unsigned char N1,N2;
void main()
{
            N1=tab1[0];
            N2=tab2[0];
}
显然,程序执行的结果是N1=0x01N2=0x10。这里都是讲数组内的数据赋值给变量,但存在区别,tab1数组使用的是单片机RAM空间,而tab2数组使用的是单片机程序存储区(ROM)空间。尽管使用C语言为变量赋值时语句相同,但编译结果并不相同,此程序编译后的结果如图6所示。
 


由编译结果可知,N1=tab1[0]语句实际上是直接寻址,而N2=tab2[0]是寄存器变址寻址。不管是何种寻址方式,都是将一个物理地址内的数据取出来使用:tab1数组中,tab[0]对应的RAM地址是0x0Atab[1]对应的RAM地址是0x0B……以此类推;tab2数组中,tab[0]对应的ROM地址是0x00A5tab[1]对应的ROM地址是0x00A6……以此类推。不管这些数组或变量所在的RAMROM地址如何,用户最终需要的是数组或变量的数据,而指针,就是通过变量或数组的物理地址访问数据,也就是说,通过指针,同样可以访问数组或变量数据。现将程序②做出调整,得到程序③如下:
#include "REG52.H"         
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char code tab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char N1,N2;
unsigned char  *p;
void main()
{        
         unsignedchar i;
         p=tab1;
         for(i=0;i<8;i++,p++)
         N1=*p;
         
         p=tab2;
         for(i=0;i<8;i++,p++) 
         N2=*p;
}
程序执行结果:tab1数组内的8个数值依次被赋值给N1tab2数组内的8个数值依次被赋值给N2
程序③执行Debug Session功能后,打Watch Windows窗口,在Watch1窗口下添加需要监视的变量,此处为“p”和“N1”,如图7所示。

Value为当前变量数值,程序为运行前,p值为0x00,单击Step按键功能后,执行p=tab1;p值变为0x0A,如图8所示。

0x0A是什么值呢?将鼠标移至tab1数组位置,可显示出数组所在的物理地址,0x0A