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

news2024/11/24 22:39:16

通用指针和定向指针

参考资料: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:通用指针和定向指针》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是Java中的finalize()方法?它有什么作用

在Java中,finalize()方法是一个由Object类定义的方法,用于在对象被垃圾回收器回收之前执行一些清理工作。finalize()方法是一个被保护的方法,可以被子类重写,但是通常情况下不需要显式地调用该方法。 finalize()方法的作用 在Jav…

MYSQL原理、设计与应用

概述 数据库(Database,DB)是按照数据结构来组织、存储和管理数据的仓库,其本身可被看作电子化的文件柜,用户可以对文件中的数据进行增删改查等操作。 数据库系统是指在计算机系统中引入数据库后的系统,除了数据库,还…

首次开通社交账号亲自招聘人才 周星驰都在关注的Web3 你知道是什么吗?

60岁的“星爷”周星驰要进军元宇宙了? 谁能想到,向来低调的他首次注册社交账号,竟是为了发布一条招人信息,挑选的还不是新片男女主角,而是Web3人才,一脚跨界到了互联网科技领域。 今天一整天,…

2022-2023 年度广东省职业院校学生专业技能大赛中职组“网络安全”赛项竞赛任务书(样题)

2022-2023 年度广东省职业院校学生专业技能大赛中职组“网络安全”赛项竞赛任务书(样题) 一、竞赛时间 总计:210 分钟 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A 模块 A-1 登录安全加固 90 分钟 200…

node笔记_express结合formidable实现前后端的文件上传

文章目录 ⭐前言⭐安装http请求的文件解析依赖库💖 安装 formidable💖 node formidable接受formData上传参数 ⭐上传的页面搭建💖 vue2 element upload💖 node 渲染 上传文件 ⭐后端生成api上传文件到指定目录💖完整的…

【Spring篇】Spring入门案例

🍓系列专栏:Spring系列 🍉个人主页:个人主页 目录 一、IOC入门案例 1.入门案例思路分析 2.入门案例代码实现 二、DI入门案例 1.入门案例思路分析 2.入门案例代码实现 三、图书推荐 介绍完Spring的核心概念后,接下来我们得思考一个问题…

2023年安徽省中职网络安全跨站脚本攻击

B-4:跨站脚本攻击 任务环境说明: √ 服务器场景:Server2125(关闭链接) √ 服务器场景操作系统:未知 √ 用户名:未知 密码:未知 1.访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交; 通过尝试知道这里存在xss漏洞

【CVE-2022-26134】Confluence OGNL RCE 漏洞

漏洞描述 远程攻击者在未经身份验证的情况下&#xff0c;可构造OGNL表达式进行注入&#xff0c;实现在Confluence Server或Data Center上执行任意代码。 影响版本 Confluence Server and Data Center > 1.3.0 Confluence Server and Data Center < 7.4.17 Confluenc…

九头蛇3389远程爆破

1.初学KALI hydra&#xff08;海德拉&#xff09;。 实验环境&#xff1a;VM16,虚拟机两台&#xff0c;Windows10系统&#xff0c;KALI系统&#xff0c;用nmap查看目标端口是否开放。 2.在KALI虚拟机上面使用命令nmap查看WIN10的3389端口是否打开。 3.在KALI虚拟机上面建立用…

Java sdk使用加载账户私钥调用合约

Java sdk使用加载账户私钥调用合约 1.智能合约案例 1.2 智能合约的流程 1.2 智能合约详细代码 实现了一个简单的商店功能。它定义了三个结构体&#xff1a;用户、商家和商品&#xff0c;以及对应的映射关系。它提供了一些方法用于注册用户和商家&#xff0c;创建商品&#x…

MVC模式和三层架构

MVC模式和三层架构 MVC模式三层架构MVC与三层架构的联系MVC与三层架构的异同 MVC模式 MVC&#xff08;Model View Controller&#xff09;是软件工程中的一种软件设计模式&#xff0c;它把软件系统分为模型、视图和控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方…

路由器+Gdbserver+IDA Pro远程调试

最近在复现路由器漏洞&#xff0c;也踩了不少坑&#xff0c;记录一下&#xff0c;希望能对需要的人有一些帮助。使用的路由器型号为RT-AC68U&#xff0c;ARM架构&#xff0c;小端序&#xff0c;Linux内核版本2.6.36&#xff0c;很老&#xff0c;主要的时间也花费在找能支持这个…

2023年最新版kali linux安装教程

一、前期准备 前排提醒&#xff0c;文末有绿色版安装包免费领取&#xff01; 二、VMware虚拟机配置 1、打开vmware&#xff0c;点击创建新的虚拟机 2、选择自定义(高级)选项&#xff0c;点击下一步 3、继续下一步 4、选择【稍后安装操作系统】&#xff0c;然后点击下一步 …

【Mybatis】使用mybatis框架连接mysql数据库详细步骤

和我之前写的通过导入jdbc驱动jar包来连接mysql数据库而言&#xff0c;用mybatis来说可以有很多好处呀&#xff0c;首先mybatis&#xff0c;就是对jdbc的优化方案对吧&#xff0c;&#xff0c;jdbc的硬编码和一些繁琐的操作在使用mybatis的时候我就彻底抛掷脑后了哈哈哈。 同时…

MySQL数据库下载及安装教程(最最新版)

MySQL数据库下载及安装教程&#xff08;最最新版&#xff09; 一、下载mysql数据库二、安装Mysql三、验证是否安装成功&#xff08;一&#xff09;、命令提示符cmd窗口验证&#xff08;二&#xff09;、MySQL控制台验证 一、下载mysql数据库 进入MySQL官方网站&#xff08;htt…

SVG实现中国地图

1.SVG是什么&#xff1f; svg 是Scalable Vector Graphics的缩写&#xff0c;指可伸缩矢量图形&#xff0c;可以用于绘制复杂不规则的控件。 svg绘制原理&#xff0c;就是利用了Path绘制图形。 1&#xff09;svg利用xml定义图形。在xml中就包晗了绘制Path所需的数据。 2&…

创建数据库中,超详细常用的MySQL命令(含解析、图解与全部代码)

目录 系统命令行 MySQL命令行 数据库命令 数据表命令 建表并导入数据 表的其他操作 系统命令行 以下是在系统命令行&#xff0c;已管理员身份运行的情况下&#xff0c;MySQL的一些命令 1.这两条是关闭MySQL服务与开启MySQL服务的命令 net stop MySQL net start MySQL80…

Mysql启动不了怎么回事

mysql 服务无法启动是什么原因&#xff1f; mysql服务无法启动的原因有很多&#xff1a;可能端口被占用&#xff1b;可能my.cnf配置了错误的参数&#xff1b;也有可能没有初始数据库&#xff0c;还有可能是其他原因。大多数原因都可以通过先注销掉原有的服务、重新装载服务、之…

ASIC-WORLD Verilog(5)基础语法下篇

写在前面 在自己准备写一些简单的verilog教程之前&#xff0c;参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好&#xff0c;奈何没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。 这是网站原文&…

k8s中pod使用详解

一、前言 在之前k8s组件一篇中,我们谈到了pod这个组件,了解到pod是k8s中资源管理的最小单位,可以说Pod是整个k8s对外提供服务的最基础的个体,有必要对Pod做深入的学习和探究。 二、再看k8s架构图 为了加深对k8s中pod的理解,再来回顾下k8s的完整架构 三、pod特点 结合上面这…