1)先记一句话
-
大端(Big-endian):高位字节在前(先看到“大的那一头”)
-
小端(Little-endian):低位字节在前(先看到“小的那一头”)
-
这里的“前/后”,指的是内存低地址→高地址的排列顺序,或者你抓到的字节流从左到右的顺序。
假设一个 16-bit 数:
0x005E(十进制 94)
它拆成两个字节:
-
高位字节(MSB)=
0x00 -
低位字节(LSB)=
0x5E
大端存放(网络字节序常用)
内存从低地址到高地址是:
地址: +0 +1
字节: 00 5E
你看到的字节流就是:00 5E
小端存放(x86/ARM 常见)
内存从低地址到高地址是:
地址: +0 +1
字节: 5E 00
✅ “结合网络中的 00 5E”:
如果这是网络包里的字段(比如端口、长度、协议字段等),一般按网络字节序=大端解释,那就是 0x005E = 94。
3)用 32 位数举例(工程里最常见)
假设 32-bit:0x12345678
拆成字节:12 34 56 78
大端(MSB在前)
12 34 56 78
小端(LSB在前)
78 56 34 12
小端 CPU 的规则是:低地址放低位字节。
以 0x12345678 为例,小端内存布局(低地址→高地址):
-
低地址:
78(最低有效字节) -
高地址:
12(最高有效字节)
5)为什么要 “read_u16_be / read_u32_be” 这种读取?
因为CPU 内存端序和协议字节序可能不一致:
-
协议/网络包:常用 大端(network byte order)
-
你的 CPU:大概率 小端
所以不能直接把 buf 强转成 uint16_t* 读(会受端序、对齐影响),要按协议规定把字节拼起来。
static inline uint16_t read_u16_be(const uint8_t* p) {
return (uint16_t(p[0]) << 8) | uint16_t(p[1]);
}
它明确表示:buf[0] 是高位,buf[1] 是低位(大端解释)。
举例:p = {0x00, 0x5E}
(0x00<<8) | 0x5E = 0x005E = 94
6)工程级常见场景举例
场景 A:TCP/UDP 端口字段
网络包里端口是 16 位大端。
抓到:00 50 → 0x0050 = 80(HTTP)
场景 B:长度字段
抓到:01 F4
按大端:0x01F4 = 500
如果你在小端 CPU 上不转换,直接读可能会变成 0xF401(完全错)。
7)最后一句工程级总结
小端 CPU:低地址放低位;
大端 CPU:低地址放高位。
协议解析时永远不要“相信 CPU 的端序”,而要自己按字节拼。
7155



被折叠的 条评论
为什么被折叠?



