C51基础之单片机编程中通用指针和定向指针

通用指针和定向指针

参考资料:Keil > Help > uVision Help > Cx51 Compiler User’s Guide > Language Extensions > Pointers

一、Cx51指针的几种用法

int *ptr;               /* 指向:任意空间的int变量,    存储在:RAM(data) 区, 占用:3字节 */
int xdata *ptr;         /* 指向:RAM(xdata)区的int变量,存储在:RAM(data) 区, 占用:2字节 */
int * xdata ptr;        /* 指向:任意空间的int变量,    存储在:RAM(xdata)区, 占用:3字节 */
int xdata * xdata ptr;  /* 指向:RAM(xdata)区的int变量,存储在:RAM(xdata)区, 占用:2字节 */

二、Cx51的指针类型

Cx51编译器支持使用符号 * 声明的指针变量,用标准C语言定义的指针变量在Cx51编译环境中可以完全兼容使用。但是,因为8051单片机独特的内存架构,Cx51编译环境提供两种不同类型的指针:

Generic Pointers-----------------通用指针

Memory-Specific Pointers-------定向指针

使用Memory-Specific Pointers可以明显的加速C语言执行效率。使用不同类型的指针,在处理相同的代码时,在代码大小、占用内存大小和执行时间上存在明显的差异。

在这里插入图片描述

三、Generic Pointers(通用指针)

声明通用指针和标准C语言用法一样,使用时通用指针可以存放任何空间的变量地址。

int *ptr;  /* 通用指针变量ptr:存储在 RAM data 区,占用3个字节空间 */

void main (void)
{
  int data  a;        /* 变量a:存储在 RAM(data)           */
  int xdata b;        /* 变量b:存储在 RAM(xdata)          */
  int code  c= 9;     /* 变量c:存储在 Flash(code)         */

  ptr = &a;           /* ptr:指向 RAM(data)  区变量的地址 */
  ptr = &b;           /* ptr:指向 RAM(xdata) 区变量的地址 */
  ptr = &c;           /* ptr:指向 Flash(code)区变量的地址 */
}

另外,用户可以通过内存类型声明,声明指针变量存放的位置,比如:

/* 这3个指针变量是Generic Pointers,分别存放在不同的内存空间 */
int  * xdata ptr_x;     /* 通用指针变量ptr_x:存储在 RAM(xdata) 区,占用3个字节空间 */
int  * data  ptr_y;     /* 通用指针变量ptr_y:存储在 RAM(data)  区,占用3个字节空间 */
int  * idata ptr_z;     /* 通用指针变量ptr_z:存储在 RAM(idata) 区,占用3个字节空间 */

四、Memory-Specific Pointers(定向指针)

定向指针在声明时,同时需要声明指向的区域,注意 * 位置。定向指针只能指向声明区域的变量,优点:有效提高代码执行效率,缺点:使用灵活性降低。

int  data  *ptr_x;     /* 定向指针变量ptr_x:指向 RAM(data)  区 */
int  xdata *ptr_y;     /* 定向指针变量ptr_y:指向 RAM(xdata) 区 */
int  code  *ptr_z;     /* 定向指针变量ptr_z:指向 Flash(code)区 */

因为内存类型在编译时确定的,所以定向指针占用的空间大小也是确定的,与8051的地址总线宽度一致。

data, idata, bdata, pdata定向指针,占用1个字节。

xdata, code定向指针,占用2个字节 。

和通用指针一样,定向指针也可以声明指针变量存储的位置,例如:

int data  * xdata ptr_x;  /* 定向指针变量ptr_x:占用2字节,存储在 RAM(xdata) 区,指向 RAM(data)  区 */
int xdata * data  ptr_y;  /* 定向指针变量ptr_y:占用1字节,存储在 RAM(data)  区,指向 RAM(xdata) 区 */
int code  * idata ptr_z;  /* 定向指针变量ptr_z:占用1字节,存储在 RAM(idata) 区,指向 Flash(code)区 */

五、指针类型转换

Cx51编译器转换通用指针和定向指针时,可以使用()强制类型转换,也可以由编译器隐式转换。

extern int printf (void *format, ...);        /* 形参:通用指针, 占用3字节 */

extern int myfunc (void code *p, int xdata *pq);  /* 形参:定向指针,占用2字节 */

int xdata *px;                                /* 变量:定向指针,占用2字节 */
char code *fmt = "value = %d | %04XH\n";      /* 变量:定向指针,占用2字节 */

void debug_print (void) 
{
  printf (fmt, *px, *px);                    /* 编译器隐式转换fmt,2字节转换为3字节 */
  myfunc (fmt, px);                          /* 类型匹配,无转换 */
}

通用指针 (*) 转换为定向指针(code *, xdata *, data *, idata *, pdata *)的过程:

在这里插入图片描述

定向指针(code *, xdata *, data *, idata *, pdata )转换为通用指针 () 的过程:

在这里插入图片描述

int *p1;                /* generic ptr (3 bytes) */
int xdata *p2;          /* xdata ptr (2 bytes) */
int idata *p3;          /* idata ptr (1 byte) */
int code *p4;           /* code ptr (2 bytes */

void pconvert (void) 
{
    p1 = p2;            /* xdata* to generic* */
    p1 = p3;            /* idata* to generic* */
    p1 = p4;            /* code*  to generic* */

    p4 = p1;            /* generic* to code* */
    p3 = p1;            /* generic* to idata* */
    p2 = p1;            /* generic* to xdata* */

    p2 = p3;            /* idata* to xdata* (WARN) */
*** WARNING 259 IN LINE 15 OF P.C: pointer: different mspace
    p3 = p4;            /* code*  to idata* (WARN) */
*** WARNING 259 IN LINE 16 OF P.C: pointer: different mspace
}

六、指针转换应用

使用抽象指针可以访问固定的存储空间,也可以调用固定地址的函数。
使用以下变量,对抽象指针进行描述。

char xdata *px;       /* ptr:指向 RAM(xdata)  区; 存储在 RAM(data) 区 */
char idata *pi;       /* ptr:指向 RAM(idata)  区; 存储在 RAM(data) 区 */
char code  *pc;       /* ptr:指向 Flash(code) 区;存储在 RAM(data) 区 */

char c;               /* char variable:存储在 RAM(data) 区 */
int  i;               /* int  variable:存储在 RAM(data) 区 */
  1. 把函数地址分配给指针
pc = (void *) main;

0000 750000  R     MOV     pc,#HIGH main
0003 750000  R     MOV     pc+01H,#LOW main
  1. data变量地址 转换为 idata指针
pi = (char idata *) &i;

0000 750000  R     MOV     pi,#LOW i

i 类型(int data),&i 类型(int data *),pi 类型(char idata *)。
i 存储在 RAM(data) 区,对 RAM(data) 间接访问就是idata,这个转换是有效的。

  1. xdata指针 转换为 idata指针
pi = (char idata *) px;

0000 850000  R     MOV     pi,px+01H

xdata指针占用2个字节, idata指针占用1个字节。进行转换时,会丢掉px的高字节,因此转换之后可能不会出现预期的效果。

  1. 常数值 转换为 code指针
pc = (char code *) 0x1234;

0000 750012  R     MOV     pc,#012H
0003 750034  R     MOV     pc+01H,#034H

把0x1234强制转换为 Flash(code) 区的地址,没有问题;

5.常数值 转换为 函数指针

 i = ((int (code *)(void)) 0xFF00) ();

0000 12FF00        LCALL   0FF00H
0003 8E00    R     MOV     i,R6
0005 8F00    R     MOV     i+01H,R7

把0xFF00强制转换为函数指针,函数原型的形参(void),返回值(int);

函数指针类型指向Flash(code) ,指针大小为2字节。

  1. 常量值 转换为 code指针,取出指针空间内的数据
c = *((char code *) 0x8000);

0000 908000        MOV     DPTR,#08000H
0003 E4            CLR     A
0004 93            MOVC    A,@A+DPTR
0005 F500    R     MOV     c,A

0x8000强制转换为code指针,取出指针空间内的数据,赋值给c。

  1. 常量值 转换为 xdata指针,取出指针空间内的数据
c += *((char xdata *) 0xFF00);

0000 90FF00        MOV     DPTR,#0FF00H
0003 E0            MOVX    A,@DPTR
0004 2500    R     ADD     A,c
0006 F500    R     MOV     c,A

0xFF00强制转换为xdata指针,取出指针空间内的数据,对c变量进行累加。

  1. 常量值 转换为 idata指针,取出指针空间内的数据
c += *((char idata *) 0xF0);

0000 78F0          MOV     R0,#0F0H
0002 E6            MOV     A,@R0
0003 2500    R     ADD     A,c
0005 F500    R     MOV     c,A

0xF0强制转换为idata指针,取出指针空间内的数据,对c变量进行累加。

  1. 常量值 转换为 pdata指针,取出指针空间内的数据
c += *((char pdata *) 0xE8);

0000 78E8          MOV     R0,#0E8H
0002 E2            MOVX    A,@R0
0003 2500    R     ADD     A,c
0005 F500    R     MOV     c,A

0xE8强制转换为pdata指针,取出指针空间内的数据,对c变量进行累加。

参考原文:《8051单片机基础6:通用指针和定向指针》

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ltqshs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值