大端和小端是计算机存储多字节数据时,字节在内存中的排列方式。
一、字节 Byte
假设有一个32位整数,它占4个字节(32bit)。
uint32_t value = 0x12345678;这个数可以拆成4个字节
0x12 0x34 0x56 0x78可以画成:
0x12345678 ┌──────┬──────┬──────┬──────┐ │ 0x12 │ 0x34 │ 0x56 │ 0x78 │ └──────┴──────┴──────┴──────┘这里 0x12 是最高字节(MSB,Most Significant Byte(最高有效字节)),0x78 是最低字节(LSB,Least Significant Byte(最低有效字节))
二、内存地址
CPU访问内存时,每个字节都有一个地址。
例如:
地址 0x1000 0x1001 0x1002 0x1003四个地址连续。
那么问题来了,0x12 放在哪?这就是大端小端的问题
三、大端
例如:
value = 0x12345678内存:
地址 数据 0x1000 ---> 0x12 0x1001 ---> 0x34 0x1002 ---> 0x56 0x1003 ---> 0x78画成图,也就是低地址放高字节,简称大高低
低地址 高地址 0x1000 0x1001 0x1002 0x1003 +-------+-------+-------+-------+ | 12 | 34 | 56 | 78 | +-------+-------+-------+-------+四、小端
地址 数据 0x1000 ---> 0x78 0x1001 ---> 0x56 0x1002 ---> 0x34 0x1003 ---> 0x12画成图,低地址放低字节
低地址 高地址 0x1000 0x1001 0x1002 0x1003 +-------+-------+-------+-------+ | 78 | 56 | 34 | 12 | +-------+-------+-------+-------+五、两者对比
假设:
value = 0x12345678大端:
地址 1000 1001 1002 1003 12 34 56 78小端:
地址 1000 1001 1002 1003 78 56 34 12注意:
value 永远都是
0x12345678没有变。只是内存排列不同。
很多初学者看到:
0x12345678会以为:
内存一定是 12 34 56 78其实这是数值的书写方式,不是内存布局。
可以把它们区分开:
- 数值表示:我们通常写成
0x12345678,最高有效字节在左,这是数学上的表示方式,与大小端无关。 - 内存布局:字节实际放在内存地址中的顺序,这才由大端或小端决定。
大端解析
static void DECODE_BYTE_VECTOR_BIGEDIAN_TO_4B(uint32_t* value_ptr, uint8_t* arr) { *((uint32_t*)value_ptr) = (uint32_t)arr[0] << 24 | (uint32_t)arr[1] << 16 | (uint32_t)arr[2] << 8 | (uint32_t)arr[3] << 0; }小端解析
第一种
static void DECODE_BYTE_VECTOR_LITTLEENDIAN_TO_4B(uint32_t *value_ptr, uint8_t *arr) { *value_ptr = ((uint32_t)arr[0] << 0) | ((uint32_t)arr[1] << 8) | ((uint32_t)arr[2] << 16) | ((uint32_t)arr[3] << 24); }第二种:直接 memcpy(仅适用于本机也是小端)
static void DECODE_BYTE_VECTOR_LITTLEENDIAN_TO_4B(uint32_t *value_ptr, uint8_t *arr) { memcpy(value_ptr, arr, sizeof(uint32_t)); }