单片机中的地址与数据到底是什么关系?一文讲透
在学习单片机或 C 语言指针时很容易产生一个疑问内存里既有数据又有地址而地址本身好像也是变量那是不是会无限“套娃”这个问题如果不彻底搞清楚后面学指针、内存映射、驱动开发都会很吃力。下面从底层结构直接讲清楚。一、内存的本质结构在单片机MCU视角下内存本质就是一个线性字节数组uint8_t MEM[N];可以理解为MEM[i]第 i 个字节i地址AddressMEM[i]数据Data所以最核心的关系只有一句话Data MEM[Address]没有链表、没有树结构、没有额外映射关系就是最简单的一维数组。二、变量是如何存储的代码int a 10;在内存中的真实形式假设int4字节小端存储地址 内容 0x1000 0x0A 0x1001 0x00 0x1002 0x00 0x1003 0x00这里可以得出a本质是地址 0x1000 的别名10是存储在这个地址上的数据三、指针的本质代码int a 10; int *p a;内存情况地址 内容 0x1000 10 // a 0x2000 0x1000 // p解释a存的是数据p存的是地址0x1000 指针的本质就是一个存储“地址值”的普通变量四、“地址也是变量”为什么不会无限套娃很多人困惑在这里地址也是变量那地址的地址呢会不会无限嵌套关键点地址本质只是一个整数例如p 0x1000;在内存中只是MEM[0x2000] 0x1000这里的0x1000只是一个数值并不会自动再去“找它的地址”只有你主动写int **pp p;才会变成pp → p → a → 数据 嵌套层数完全由代码决定不存在无限递归。五、CPU如何区分“地址”和“数据”结论很重要CPU根本不区分地址和数据区别来自指令的使用方式。1. 当作普通数据使用int x p;CPU行为x MEM[0x2000] → 0x1000 把地址当作普通整数2. 当作地址使用解引用int x *p;CPU行为1. 取 p 的值 → 0x1000 2. 访问 MEM[0x1000] → 10 这里才发生“间接访问”六、硬件角度的访问过程单片机访问内存依赖三类信号地址总线Address Bus传地址数据总线Data Bus传数据控制信号读/写一次读操作本质是CPU 地址总线 → 0x1000 发出读信号 内存 返回 MEM[0x1000] → 数据 地址只是“输入信号”不是内存里的对象。七、本质总结可以把整个模型压缩成 4 句话内存 一维字节数组 MEM[]地址 数组下标数据 MEM[地址]指针 存储地址的变量以及最关键的一点是否把一个值当作地址使用取决于指令是否解引用而不是数据本身八、延伸为什么外设寄存器也像变量在单片机中常见*(volatile uint32_t *)0x40021018 0x01;这里的本质仍然是MEM[0x40021018] 0x01; 外设寄存器只是被映射到某个地址空间本质和变量没有区别。结尾很多人卡在“地址是不是变量”这个问题本质是因为把“地址”当成了一种特殊对象。实际上地址只是一个整数只有在被当作索引访问内存时才具有“指针意义”。理解这一点之后指针内存映射操作系统内存管理驱动开发都会顺很多。