字节序(Endianness)
含义
在计算机系统中,数据是以字节为单位进行存储和访问的。字节序描述的是在一个多字节数据(如 int、float 等)中,各个字节的排列顺序。
大端序(Big Endian)
- 存储顺序:高位字节存储在内存的低地址处,低位字节存储在高地址处。即
高位在前,低位在后。 - 例如:一个 4 字节的整数 0x12345678:
内存地址: 0x00 0x01 0x02 0x03
存储内容: 0x12 0x34 0x56 0x78
- 特点:这种字节序符合人类从左到右的阅读习惯,所以常用于网络协议(也被称为网络字节序 Network Byte Order)和某些文件格式(如 PNG、JPEG 等)。
小端序(Little Endian)
- 存储顺序:低位字节存储在内存的低地址处,高位字节存储在高地址处。即
低位在前,高位在后。 - 例如:一个 4 字节的整数 0x12345678:
内存地址: 0x00 0x01 0x02 0x03
存储内容: 0x78 0x56 0x34 0x12
- 特点:相当于在倒着写。由于小端序更贴近 CPU 的硬件设计逻辑(尤其是在加法、移位操作中),因此
x86和x86_64架构都采用小端序,部分ARM处理器支持双端序模式(可切换)。
词源
这个词最早由计算机科学家 Danny Cohen 在 1980 年的论文《On Holy Wars and a Plea for Peace》中提出,灵感来源于乔纳森·斯威夫特的小说《格列佛游记》。
在小说中,小人国的居民因为吃鸡蛋时是先敲大头(Big End)还是先敲小头(Little End)而分裂成两个阵营,引发了战争。

Cohen 用这个比喻来形容计算机系统在处理字节顺序时的分歧。大端序和小端序的根本区别就是:在内存低地址处存放的是高位字节(大端序)还是低位字节(小端序)。
判断字节序的代码 (C/C++)
#include <iostream>
bool isLittleEndian() {
int num = 1;
// 将 int 的地址转换为 char* 指针,读取第一个字节
char* ptr = reinterpret_cast<char*>(&num);
// 如果第一个字节是 1,说明是小端序
return (*ptr == 1);
}
int main() {
if (isLittleEndian()) {
std::cout << "当前系统是小端序 (Little Endian)" << std::endl;
} else {
std::cout << "当前系统是大端序 (Big Endian)" << std::endl;
}
return 0;
}
原理说明:
- 整数
1的十六进制表示为0x00000001(32位) - 小端序:内存中存储为
01 00 00 00,第一个字节是0x01 - 大端序:内存中存储为
00 00 00 01,第一个字节是0x00
字节序转换函数
在网络编程中,经常需要在主机字节序和网络字节序之间转换:
#include <arpa/inet.h> // Linux/Unix
// #include <winsock2.h> // Windows
// 主机字节序 → 网络字节序(大端序)
uint32_t host_val = 0x12345678;
uint32_t net_val = htonl(host_val); // [h]ost [to] [n]etwork [l]ong
uint16_t net_short = htons(host_val); // [h]ost [to] [n]etwork [s]hort
// 网络字节序 → 主机字节序
uint32_t host_val2 = ntohl(net_val); // [n]etwork [to] [h]ost [l]ong
uint16_t host_short = ntohs(net_short); // [n]etwork [to] [h]ost [s]hort
比特序(Bit Endianness)
除了字节序,还存在比特序的概念。
什么是比特序?
比特序描述的是在一个字节内部,各个比特位的排列顺序。
- MSB(Most Significant Bit First):最高有效位在前,类似大端序
- LSB(Least Significant Bit First):最低有效位在前,类似小端序
比特序的应用场景
- 串行通信协议:如
UART、SPI、I2C等,需要规定比特的传输顺序 - 位操作和位域:在某些嵌入式系统或网络协议中,需要精确控制比特顺序
- 硬件寄存器:不同芯片厂商对寄存器的比特编号方式可能不同
示例:位域的比特序问题
struct BitField {
unsigned int a : 1; // 占 1 位
unsigned int b : 2; // 占 2 位
unsigned int c : 5; // 占 5 位
};
在不同的编译器和架构下,这些位域在字节中的排列顺序可能不同,这就是比特序的影响。
注意:C/C++ 标准并未规定位域的内存布局,因此在跨平台或底层硬件编程时需特别小心。
实际应用中的注意事项
1. 网络编程
TCP/IP协议栈使用大端序(网络字节序)- 发送数据前需要将主机字节序转换为网络字节序
- 接收数据后需要将网络字节序转换为主机字节序
2. 文件格式
- 某些文件格式(如
PNG、JPEG)使用大端序 - 某些文件格式(如
BMP、GIF)使用小端序 - 读写文件时需要注意字节序转换
3. 跨平台开发
- 不同架构的机器可能使用不同的字节序
- 数据交换时必须明确约定字节序
- 可以使用序列化库(如
Protocol Buffers、MessagePack)来自动处理字节序问题
4. 性能考虑
- 字节序转换本身有性能开销
- 在高性能场景下,尽量减少不必要的转换
- 某些 CPU 提供专门的字节序转换指令(如 x86 的
bswap)
总结
| 对比项 | 大端序 | 小端序 |
|---|---|---|
| 存储方式 | 高位在前,低位在后 | 低位在前,高位在后 |
| 可读性 | 符合人类阅读习惯 | 不太直观 |
| 应用场景 | 网络协议、部分文件格式 | x86/x64 CPU、大多数嵌入式系统 |
| 硬件效率 | 一般 | 更高(便于加法、移位等操作) |
核心要点:
- 字节序只影响多字节数据的存储顺序
- 单字节数据(如
char)不受字节序影响(宽字符wchar是受影响的) - 网络传输统一使用大端序
- 比特序在特定场景(串行通信、硬件寄存器)中需要关注
- 跨平台开发时要注意字节序转换
默认评论
Halo系统提供的评论