一、大小端模式介绍
1. 先搞懂:为什么要有大小端?
我们知道:
- 1 个字节 = 8 bit
- 但计算机里的 int、long、地址 都是 多字节(比如 4 字节)
问题来了:
一个 4 字节的数,存到内存里,高字节放前面,还是低字节放前面?
两种方案 → 就是 大端 / 小端。
2. 举个最经典例子
假设有一个 32位整数:
0x12345678
拆成 4 个字节(从高到低):
- 最高字节:
0x12 - 然后:
0x34 - 然后:
0x56 - 最低字节:
0x78
内存地址从小到大:0x100 0x101 0x102 0x103
① 大端模式(Big-Endian)
高字节存低地址,和人类读写习惯一样
内存:
0x100: 0x12
0x101: 0x34
0x102: 0x56
0x103: 0x78
特点:
- 符合人类阅读顺序
- 网络传输、ARM 在某些模式、部分单片机常用
② 小端模式(Little-Endian)
低字节存低地址,和人类反过来
内存:
0x100: 0x78
0x101: 0x56
0x102: 0x34
0x103: 0x12
特点:
- x86、x86_64(电脑CPU)全是小端
- 计算机硬件计算更方便
3. 一句话总结(超好记)
- 大端:高位在前,和人看书一样
- 小端:低位在前,和人反过来
4. 你做嵌入式/单片机一定会遇到的场景
-
串口、SPI、I2C、网络通信
协议一般是 大端 ,但你的 MCU 可能是小端,直接发数据会发反。
-
强制类型转换、指针强转
比如:
c
int a = 0x12345678;
char *p = (char*)&a;
- 大端:
*p = 0x12 - 小端:
*p = 0x78
- 读写Flash、寄存器、协议解析
大小端搞错,数据一定是错的。
5. 超简口诀
高对低(地址)是大端,低对低是小端
二、大端模式实际场景
16位数0x1234赋值给32位数
| 内存地址 (由低到高) | 大端模式下的存放内容 | 说明 |
|---|---|---|
| 低地址 | 0x00 |
最高字节 (MSB) |
| ↓ | 0x00 |
|
| ↓ | 0x12 |
原16位数的高字节 |
| 高地址 | 0x34 |
最低字节 (LSB) |
16位数0x1234赋值给4字节数组
| 数组索引 | 地址(相对) | 存储的内容(字节) | 说明 |
|---|---|---|---|
arr[0] |
低地址 | 0x12 |
高字节(高位) |
arr[1] |
高地址 | 0x34 |
低字节(低位) |
arr[2] |
更高地址 | (未知) | 数组后续元素,不受影响 |
arr[3] |
最高地址 | (未知) | 数组后续元素,不受影响 |
1、场景一
在 UM800Y 这款大端模式的 8051 芯片中,如果你把一个 16 位的数(比如 unsigned int)赋值给一个 4 字节的数组,这个 16 位数在数组中的存放规则是:高字节(高位)存放在数组的低索引字节,低字节(低位)存放在数组的高索引字节。
举个例子让你更清楚地理解
假设:
- 你有一个 16 位的数值:
0x1234(这里0x12是高字节,0x34是低字节)。 - 你定义了一个 4 字节的数组:
unsigned char arr[4]。 - 你将这个 16 位数赋值给数组,比如通过指针操作或共用体。
那么,在内存中的实际存放结果将是:
| 数组索引 | 地址(相对) | 存储的内容(字节) | 说明 |
|---|---|---|---|
arr[0] |
低地址 | 0x12 |
高字节(高位) |
arr[1] |
高地址 | 0x34 |
低字节(低位) |
arr[2] |
更高地址 | (未知) | 数组后续元素,不受影响 |
arr[3] |
最高地址 | (未知) | 数组后续元素,不受影响 |
如果用代码来直观感受一下
你可以通过下面的 C 代码来验证这种存放方式:
c
#include <stdio.h>
void main() {
// 定义一个16位的数值
unsigned int value = 0x1234;
// 定义一个4字节的数组
unsigned char arr[4] = {0};
// 将16位数值的地址强制转换为字节指针,
// 这样就可以按字节访问value在内存中的内容
unsigned char *p = (unsigned char *)&value;
// 将value的字节内容复制到数组的前两个元素中
arr[0] = p[0]; // 在8051大端模式下,p[0]指向高字节 0x12
arr[1] = p[1]; // p[1]指向低字节 0x34
// 如果你debug查看arr的内容,会看到:
// arr[0] == 0x12
// arr[1] == 0x34
}
为什么是这样?
这完全是由 UM800Y 芯片的内核架构决定的。它使用的是 1T 8051 内核,完全兼容传统 8051 的指令代码 。而标准的 8051 架构在处理多字节数据(如 16 位的地址和 int 类型)时,采用的是大端格式。
2、场景二
在 UM800Y 芯片(大端模式)中,将一个16位的数赋值给一个32位的数,关键在于区分数值转换 和内存存放这两个概念。
简单来说,结论是:
- 数值上:16位数会被完整地、原样地赋值给32位数(存放在低位)。
- 内存中 :这个32位数作为一个整体,在内存中的存放规则依然遵循芯片的大端模式。
我们用一个例子来具体看:
假设16位数是 0x1234。当你把它赋值给一个32位的变量(比如叫 value_32)后,这个 value_32 的数值 就变成了 0x00001234。也就是说,它在高位补了16个0。
现在,这个值为 0x00001234 的32位数,在UM800Y的大端模式下,内存地址从低到高的存放顺序会是:
| 内存地址 (由低到高) | 大端模式下的存放内容 | 说明 |
|---|---|---|
| 低地址 | 0x00 |
最高字节 (MSB) |
| ↓ | 0x00 |
|
| ↓ | 0x12 |
原16位数的高字节 |
| 高地址 | 0x34 |
最低字节 (LSB) |
所以,这个过程可以拆解成两步来理解:
-
第一步:数值赋值 (确定"是什么")
当你写下
uint32_t value_32 = 0x1234;这行代码时,从C语言的逻辑层面看,value_32这个变量里的值就被确定为了0x00001234。这个过程和你之前问的"将16位数赋值给4字节数组"里的arr[2]和arr[3]无关,它们是不同的内存操作。 -
第二步:内存存放 (确定"怎么放")
这个数值
0x00001234在物理内存中怎么存放,就完全由UM800Y的大端模式决定了。- 大端模式的核心规则 :数据的高字节 (这里是
0x00)放在内存的低地址 ;数据的低字节 (这里是0x34)放在内存的高地址 。 - 因此,这个32位的数在内存中,就是按顺序存放
0x00,0x00,0x12,0x34。
- 大端模式的核心规则 :数据的高字节 (这里是
简单来说
如果你关心的是 value_32 这个变量的值,它就是 0x00001234。
如果你通过指针,以字节为单位去查看 value_32 在内存中的样子,就会看到 0x00, 0x00, 0x12, 0x34 这个顺序。