对单片机C语言指针的一些理解

指针在单片机C语言里面占有重用地位,但是指针也是单片机C语言里面可以说是最难以理解的一个点。C语言属于高级语言,但是指针却有汇编语言的特性,因此如果只讲指针,不讲硬件,那么听起来就会感觉再云里雾里。如果学过汇编,了解过单片机的底层结构,那么理解指针就容易得多,指针相当于汇编里面是直接寻址,寄存器间接寻址,但是比两种寻址会更加灵活和方便,无需进行寄存器选择和寄存器操作,因为已经进行了归一化/格式化处理。。

面下面我就用对房子进行类比(RAM空间),然后说一说我对指针的理解。

1.指针是什么

通俗一点讲指针就是内存空间的一个值,这个值存着地址(RAM空间或是ROM空间地址)。如果不说它是指针,那么和普通内存的数据没有什么区别。

只是在应用的时候会根据不同类型的指针加载在不同的寄存器里面,用于干不同的事情。

2.指针的作用

指针的作用就是寻址,当找到对应的地址了,就可以对地址空间相对应的内容进行处理。

3.指针本身宽度

首先,单片机体系决定了指针本身的的存储宽度,也就是说不管是什么类型(u8*,u16*,u32*,注意有些单片机是不支持u32*指针的)的指针,其宽度都一样。

因为指针本身就是内存里面的数据,只是这个数据用于表示数据空间/程序空间地址,或是说指向某个地址。在不同的单片机体系中,指针本身的宽度不一样,由单片机的架构决定本身宽度。

比如应广单片机指针,本身占用2个字节

比如51指针,本身占用3个字节,

比如M0指针,本身占用4个字节。

单片机的架构决定指针本身的数据宽度,那为啥还会有指针的类型(宽度)。此宽度非彼宽度,前者指的是指针本身宽度,占内存多少字节;后者指针类型(宽度)是指:指针指向的地址的数据类型的类型(宽度)

4.指针类型(指针指向的数据的宽度)

**指针类型:**指的指针指向目的地址的数据类型的宽度,也叫指针类型,比如有u8*,u16*,u32*。

u8*pucBuilding;/**/

u16*pusBuilding;

u32*puiBuilding;

比如 定义的是u8*,那么pucBuilding++; 实际地址空间就增加1byte

定义的是u16*,那么pusBuilding++; 实际地址空间就增加2byte

定义的是u32*,那么puiBuilding++; 实际地址空间就增加4byte

让使用指针的时候,针对不同的数据类型,能够方便快捷地找到对应地址,并进行对应的操作

为什么说指针难学,另外一个原因就是缺少明确的表述,相当于间接操作,要区分源和目的,还有类型。

5**.绝对地址指针(类比汇编直接寻址,C语言** 一般比较少这样用,但理解指针要从这里开始**)**

绝对地址指针可以指向内存空间的任意地址。

来个比喻,比如在楼栋里面,共8楼,每楼有16套房子,(8*16=128,其实这个房子就是内存空间)。你说你是208,人家就知道你是2楼8号

101->0x00

102->0x01

201->0x10

208->0x17

.......

508->0x57

可以用 u8 * pucBuilding=(*u8)0x17(绝对地址),C语言的意思就是,把这个0x17强制转换成地址,并使这个指针pucBuilding指向1byte宽度的数据空间0x17.相当于直接告诉房号,然后找房子。

只要定义了一个指针,就可以指向数据空间的任意地址,除了可以覆盖指向任意一个房号(101-816)外,其有能力指向不存在在空间,因为指针的宽度是由单片机体系结构决定的,也就是说指针本身可以表示一个很大的值,比如应广的指针式16bit宽度,可以表示的地址范围(0-0xffff),实际上内存空间可能只有64byt/80byte;

当*pucBuilding=(*u8)0x27, 对应就是3楼8号房

* pucBuilding=(*u8)0xF8,对应指向16楼8号房(实际不存在),指针有这个能力,但是不一定可用。

一旦确定内存空间范围(1-128),那么在使用指针的时候,就要对这个指向的范围加以限制,否则就可能出现系统异常,溢出或死机。

* pucBuilding=(*u8)0xF8中,pucBuilding使指向就是那空中楼阁,如果要对指针指向的数据进行操作,那么那么就出现溢出了,因为单片机只有128byt的RAM空间。

当然,如果只有128个内存空间,如果要是用u16 * pucBuilding=(*u16)0x0f,也没有关系,但是操作数据的时候就要注意,这个指针是按照16bit宽度进行数据操作,也就是两间房合并成一间房子,用同样一个编号。

不管使用的是任何类型指针,指针的操作,都一定要限制其操作范围,否则可能出现异常,溢出,甚至还会引起死机等问题。

在绝对寻址里面,其指向范围是可以整个内存空间,包括不存在的空间,这个就要注意了,要先了解内存结构,再用这个指针。

使用指针前,一是确定指针是范围,二是确定指针类型,两者缺一不可

指针的范围确认,指针才不会指向空中楼阁

指针的类型确认,指针一次性是操作几个字节

u8*指针眼里,内存是按照byte为单元顺序排列

u16*指针眼里,内存是按照2byte为一个单元顺序排列

u32*指针眼里,内存是按照4byte为一个单元顺序排列

6.相对地址指针(寄存器间接寻址,这个比较常用)

绝对指针可以指向数据空间的任意地方,给什么地址,就指向什么地址;

而相对指针是指向内存空间的某个区块,一般这个地址来自某个已经分配好内存空间的数据块所在的空间,比如数组,比如结构体。其限定范围是就是这个区块,属于间接得到这个地址。

比如定义了一个 u8 aucDat[8];/*如果不指定其绝对地址,那么这个数组可能存放在内存空间的任意位置*/

比如 aucDat[0]=0x23;

aucDat[1]=0x01;

u8 * pucBuilding=&aucDat[0];/*间接地址,不管这个数组存在任何数据空间的位置,只要知道其首地址,就能对其进行操作*/

意思是把这个数组的首地址赋给pucBuilding,

u8 dat=* pusBuilding;/*那么得到dat为0x23,*/

从这边就可以回答一个问题就是,为什么数组的标号不能当指针用,因为数组标号就只是一个标号,数组的标号并不占用内存空间,里面存的是数组的内容,因此无法当作指针用用。

那么通过pucBuilding指针就可以操作任何数组的任意一个值了.这个指针里面存的值就是数组的首地址

pucBuilding++;/*指向aucDat[1]*/

如果数组中存的4个是16位数据,相当于两个byte合成一个16bit数据。

其实也可以 定义u16 * pusBuilding=(u16 *)&aucDat[0];

这样通过指针,就可以按照16bit 数方式操作这个数组了。

u16 dat=* pusBuilding;/*dat=0x0123,假如单片机是小端模式*/

使用指针的好处就是灵活,相当于知道对方的门牌号码,找到之后就可以很方便进行对应的数据操作,指哪里打哪里,直接上门服务。也就是无需通过数据搬移传递,更新,然后再搬回;直接再在对应地址操作就行了。这样就可以大大减少数据传递和搬移时间,提高运算速度和效率,也减少内存空间的使用。

但是因为指针对数据操作的功能非常强大,如果不进行范围限制,那么可能有一定破坏性。任何强大的东西都有两面性,因此再次强调一点就是,对指针操作前一定要注意限制其范围,一定要再指定的范围内使用,防止指针越界。

7**.函数指针**

其实这个和数组指针是差不多,只不过指向的是程序空间地址。

总结

一,指针本身占内存空间,

二,这个内存空间存着地址,也可以说是指向一个地址

三,这个内存空间指向的地址同样存储着数据(可能也是地址喔,二级指针)

四,这些数据可以按照不同的数据类型来操作

五,通过指针操作这些数据的时候,要限定指针的操作范围。

只要掌握了指针原理,所有指针用法都几乎一样,就是找到对应要操作数据的内存/程序的位置,然后再进行对应的操作。再三强调一下,使用指针的时候必须限制其范围,否则会带来很多莫名奇怪的问题,这种问题往往非常隐秘,这种问题定位也很困难,也可能很久不出问题,但是往往一出问题就是致命问题。

总之, c语言指针就是把汇编的寻址方式归一化,方便大家直接操作地址空间所对应的值。希望大家学好指针,用好指针,可以指哪里打哪里,不用周转,不用拐弯,直接上门服务就完事了。希望大家喜欢,水平有限,欢迎指正。

相关推荐
im_AMBER2 小时前
Leetcode 102 反转链表
数据结构·c++·学习·算法·leetcode·链表
朔北之忘 Clancy3 小时前
2025 年 9 月青少年软编等考 C 语言一级真题解析
c语言·开发语言·c++·学习·数学·青少年编程·题解
Xの哲學3 小时前
深入剖析Linux文件系统数据结构实现机制
linux·运维·网络·数据结构·算法
C雨后彩虹3 小时前
竖直四子棋
java·数据结构·算法·华为·面试
你怎么知道我是队长4 小时前
C语言---缓冲区
c语言·开发语言
2501_927773074 小时前
嵌入式51单片机
单片机·嵌入式硬件·51单片机
荒诞硬汉4 小时前
对象数组.
java·数据结构
散峰而望5 小时前
【算法竞赛】栈和 stack
开发语言·数据结构·c++·算法·leetcode·github·推荐算法
恶魔泡泡糖5 小时前
51单片机独立按键
单片机·嵌入式硬件·51单片机