17 大小端与协议字节序
核心记忆:小端低字节先放;大端高字节先放。以协议规定为准,不以 CPU 字节序为准。
1. 一张图看懂
16 位数 0x1234 分成高字节 0x12 与低字节 0x34。下图从左到右表示地址由低到高。
低地址 ─────────→ 高地址
小端 Little Endian ┌─────────┬─────────┐
│ 0x34 │ 0x12 │
│ 低字节 │ 高字节 │
└─────────┴─────────┘
大端 Big Endian ┌─────────┬─────────┐
│ 0x12 │ 0x34 │
│ 高字节 │ 低字节 │
└─────────┴─────────┘
| 对比 | 小端(Little Endian) | 大端(Big Endian) |
|---|---|---|
| 低地址处 | 低有效字节 | 高有效字节 |
数值 0x1234 的传输/存储顺序 | 34 12 | 12 34 |
| 两字节解析 | 第 2 字节左移 8 位 | 第 1 字节左移 8 位 |
2. 代码:两个字节怎么拼成 uint16_t
假设 buf 已包含两个有效字节:
uint8_t buf[2] = {0x12, 0x34};
uint16_t le = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); // 0x3412
uint16_t be = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1]; // 0x1234
看谁左移 8 位,就是谁放到高字节。 这种显式移位拼接方法不依赖 CPU 本机的大小端。
3. 蓝牙/TWS:命令包示意
某自定义协议示例(并非通用蓝牙命令格式):命令号 1 字节 + 小端参数 2 字节。
字节下标 buf[0] buf[1] buf[2]
┌───────────┬───────────┬───────────┐
命令内容 │ 0x01 │ 0x34 │ 0x12 │
└───────────┴───────────┴───────────┘
含义 命令号 参数低字节 参数高字节
└──→ value = 0x1234
uint8_t cmd[3] = {0x01, 0x34, 0x12};
uint16_t value = (uint16_t)cmd[1] | ((uint16_t)cmd[2] << 8);
// value == 0x1234
4. 最后记忆
- 小端:先低后高。大端:先高后低。
- 字节序规定的是多字节整数的字节排列顺序,不是数值本身发生改变。
- 先看协议文档,再决定拼接顺序;不要直接按 CPU 大小端猜测报文格式。
- 本节只讨论字节序;长度和边界检查见第 15 篇。