指针变量的定义与一般变量的定义类似,其一般形式如下:
数据类型 [存储器类型1]*[存储器类型2] 标识符;
其中“标识符”是所定义的指针变量名。
“数据类型”说明该指针变量所指向的变量的类型。
“存储器类型1”和“存储器类型2”是可选项,它是Keil C51编译器的一种扩展,如果带有“存储器类型1”选项,指针被定义为基于存储器的指针,无此选项时,被定义为一般指针。这两种指针的区别在于它们的存储字节不同。一般指针在内存中占用3个字节,第一个字节存放该指针的存储器类型编码(由编译时编译模式确定),第二个和第三个字节分别存放该指针的高位和低位地址偏移量。存储器类型1编码值如下:
“存储器类型2”选项用于指定指针本身的存储器空间。
一般指针可用于存取任何变量而不必考虑变量在8051单片机存储器空间的位置,许多C51库函数采用了一般指针,函数可以利用一般指针来存取位于任何存储器空间的数据。下面是一个一般指针定义的例子,同时给出了汇编语言代码,请注意汇编语言代码中指针第一个字节是存储器类型编码值,第二、三字节是地址偏移量。
下面是Keil C51定义一般指针的语句:
上面一般指针c_ptr、i_ptr、l_ptr全部位于8051单片机的片内数据存储器中,如果在定义一般指针时带有“存储器类型2”选项,则可指定一般指针本身的存储器空间位置,例如:
由于一般指针所指对象的存储器空间位置只有在运行期间才能确定,编译器在编译时无法优化存储方式,必须生成一般代码以保证能对任意空间的对象进行存取,因此一般指针所产生的代码运行速度较慢,如果希望加快运行速度则应采用基于存储器的指针。基于存储器的指针所指对象具有明确的存储器空间,长度可为1个字节(存储器类型为IDATA、DATA、PDATA)或2个字节(存储器类型为CODE、XDATA),例如:
与一般指针类似,若定义时带有“存储器类型2”选项,则可指定基于存储器的指针本身的存储器空间位置,例如:
基于存储器的指针长度比一般指针短,可以节省存储器空间,运行速度快,但它所指对象具有确定的存储器空间,缺乏灵活性。在一些函数调用中进行参数传递时需要采用一般指针,例如,C51的库函数printf()、sprintf()、gets()等便是如此。当传递的参数是基于存储器的指针时,若不特别指明,Keil C51编译器会自动将其转换为一般指针。
一般指针与基于存储器的指针转换规则如下(一般指针用GP表示)。
GP→xdata:使用GP的偏移部分(2字节)。
GP→code:同上。
GP→idata:使用GP偏移部分的低字节,高字节不用。
GP→data:同上。
GP→pdata:同上。
xdata→GP:一般指针的存储器类型编码被设定为0x01,使用xdata*的双字节偏移量。
code→GP:一般指针的存储器类型编码被设定为0xFF,使用code*的双字节偏移量。
idata→GP:一般指针的存储器类型编码被设定为0x00,指针的一字节偏移量被转换为unsigned int类型。
data→GP:同上。
pdata→GP:一般指针的存储器类型编码被设定为0xFE,指针的一字节偏移量被转换为unsigned int类型。
例2-40 指针转换。