计算机字节序(Endianness)
高低顺序约定
- 内存地址: 通常约定从左到右内存地址从小到大
- 字节位: 通常约定左高位,右低位
基本概念
字节序描述多字节数据在内存中的存储顺序。
| 类型 | 存储方式 | 示例:0x12345678 |
|---|---|---|
| 大端序 | 最高有效字节存低地址,即低位对高地址 | [12] [34] [56] [78] |
| 小端序 | 最低有效字节存低地址,即低位对低地址 | [78] [56] [34] [12] |
常见架构:
- 小端:x86/x64
- 大端:网络协议、PowerPC
- 可配置:ARM
多字节数据 vs 字节序列
核心区别
| 类型 | 示例 | 是否有字节序 |
|---|---|---|
| 多字节数据 | int32, float32 | 有 |
| 字节序列 | UTF-8, string | 无 |
判断标准
“交换两个字节的位置,还是同一个东西吗?”
- 是 → 有字节序(int32交换后还是同一个数,只是表示不同)
- 否 → 无字节序(UTF-8交换后解码失败)
字节存储
比如常量:
const x = 0x12345678 // 这是字节位作为 int32(有字节序)
var x int32 = 0x12345678- 小端内存:
[78 56 34 12] - 大端内存:
[12 34 56 78]
作为字节序列(无字节序)
b := []byte{0x12, 0x34, 0x56, 0x78}- 所有系统:
[12 34 56 78](按索引固定顺序)
寄存器与内存映射
寄存器特点
- 寄存器无字节序概念,只有高位(bit31)和低位(bit0),假设32位系统。
- 多字节读取指令(如
MOV EAX)会按系统字节序映射
小端系统映射
规则:低地址 → 寄存器低位
大端系统映射
规则:低地址 → 寄存器高位
整块复制逻辑
核心:硬件按字节序读写,不关心数据类型
不管是 int32 还是 string,整块复制时都走相同的字节序映射,即根据大小端来映射。
网络传输与转换
网络字节序标准
- 网络字节序 = 大端序(TCP/IP规定)
- 所有多字节整数必须按大端传输
转换责任
flowchart LR subgraph Sender["发送方(小端)"] S1["主机数据<br/>[90 1F 00 00]<br/>port=8080"] end subgraph Network["网络传输"] N1["[00 00 1F 90]"] end subgraph Receiver["接收方(小端)"] R1["主机数据<br/>[90 1F 00 00]<br/>port=8080"] end S1 -->|"htonl<br/>小端↔大端"| N1 N1 -->|"ntohl<br/>大端↔小端"| R1
| 函数 | 作用 | 说明 |
|---|---|---|
htonl() | 主机 → 网络 | 小端转大端,大端无操作 |
ntohl() | 网络 → 主机 | 大端转小端,大端无操作 |
各层责任
flowchart TB subgraph AppLayer["应用层"] AppData["应用层数据<br/>(自定义协议字段)"] AppHandle["用户程序处理<br/>htonl/ntohl"] end subgraph TransportLayer["传输层"] TcpHeader["TCP/UDP头部<br/>(端口号、序列号等)"] Kernel1["内核自动处理"] end subgraph NetworkLayer["网络层"] IpHeader["IP头部<br/>(IP地址、包长度等)"] Kernel2["内核自动处理"] end subgraph LinkLayer["数据链路层"] Frame["以太网帧<br/>(MAC地址、CRC等)"] Hardware["驱动/硬件处理"] end AppData --> AppHandle AppHandle --> TcpHeader TcpHeader --> Kernel1 Kernel1 --> IpHeader IpHeader --> Kernel2 Kernel2 --> Frame Frame --> Hardware
关键API
// C
uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);// Go
binary.BigEndian.PutUint32(buf, val) // htonl
binary.BigEndian.Uint32(buf) // ntohl与序列化的关系
| 方式 | 处理 |
|---|---|
| 手动二进制 | 显式调用 htonl/ntohl |
| Protocol Buffers | 库自动处理(推荐) |
| JSON/XML | 无需处理(文本无字节序) |
核心总结
- 字节序只针对多字节数据(int/float),字节序列(UTF-8/string)无字节序
- 寄存器读取按系统字节序映射:
- 小端:低地址→寄存器低位
- 大端:低地址→寄存器高位
- 网络传输统一用大端:发送方htonl,接收方ntohl
- 整块复制无问题(读写用同一规则),跨系统传输需转换
- 使用序列化库(Protobuf)可自动处理