- BC20280018's blog
大端小端
- 2025-9-19 10:49:35 @
核心概念:字节序(Byte Order)
首先,要明白这个概念只针对多字节(multi-byte)的数据类型,例如 int (通常4字节), short (通常2字节), float (4字节) 等。对于单字节的 char,则无所谓大端小端。
字节序,指的是当一个多字节的数据存放在内存中时,它的各个字节在内存地址中的排列顺序。
生动的比喻
想象一下你写一个数字“1234”。
- 大端 (Big-Endian):就像你写数字一样,最重要的部分(“大头”)在前。你先写 1,然后是 2,3,4。
- 小端 (Little-Endian):反过来,最不重要的部分(“小头”)在前。你会先写 4,然后是 3,2,1。
在计算机中,“重要”的部分指的是高位字节 (Most Significant Byte, MSB),“不重要”的部分指的是低位字节 (Least Significant Byte, LSB)。
详细定义与图解
假设我们有一个4字节的十六进制整数 0x12345678,它要被存放到从地址 0x100 开始的内存中。
- 高位字节 (MSB) 是 0x12
- 低位字节 (LSB) 是 0x78
- 大端序 (Big-Endian)
定义:高位字节存放在低地址,低位字节存放在高地址。这也被称为“网络字节序”,因为它符合人类阅读习惯。
存储方式:
┌──────────┬──────────┐ │ 内存地址 │ 存储内容 │ ├──────────┼──────────┤ │ 0x100 │ 0x12 │ │ 0x101 │ 0x34 │ │ 0x102 │ 0x56 │ │ 0x103 │ 0x78 │ └──────────┴──────────┘
- 小端序 (Little-Endian)
定义:低位字节存放在低地址,高位字节存放在高地址。
存储方式:
┌──────────┬──────────┐ │ 内存地址 │ 存储内容 │ ├──────────┼──────────┤ │ 0x100 │ 0x78 │ │ 0x101 │ 0x56 │ │ 0x102 │ 0x34 │ │ 0x103 │ 0x12 │ └──────────┴──────────┘
谁在使用?
-
大端 (Big-Endian):
- TCP/IP协议:网络传输协议规定使用大端序,所以它也被称为网络字节序 (Network Byte Order)。
- CPU架构:PowerPC (旧款Mac), SPARC, MIPS, IBM Mainframes。
- 文件格式:JPEG, PNG 等。
-
小端 (Little-Endian):
- CPU架构:Intel x86, x86-64 (绝大多数个人电脑、服务器), AMD, 以及绝大多数情况下的 ARM 架构 (手机、嵌入式设备)。
- 文件格式:BMP, GIF 等。
-
双端 (Bi-Endian):
- 一些现代CPU架构(如 ARM, MIPS)可以配置成大端或小端模式工作。
为什么这个概念很重要?
当两台使用不同字节序的计算机进行通信或交换文件时,就会出现问题。
例子:一台使用小端序的电脑(比如你的笔记本)要通过网络发送整数 0x12345678。
- 在你的电脑内存中,它是 78 56 34 12。
- 为了遵循TCP/IP协议,发送程序必须把它转换成网络字节序(大端):12 34 56 78。
- 数据在网络中以 12 34 56 78 的顺序传输。
- 接收方(可能是一台大端服务器)直接按 12 34 56 78 的顺序读入内存,就能正确解析出 0x12345678。
- 如果接收方也是小端电脑,它会再把网络字节序转换回本地的小端字节序 78 56 34 12。
如果不进行转换,小端机直接发送 78 56 34 12,大端机接收后会把它误读为 0x78563412,这就导致了数据错误。
为此,编程语言和库通常提供函数(如C语言中的 htons, htonl, ntohs, ntohl)来在这两种字节序之间进行转换。
如何检测本机的字节序?
你可以用一小段C代码来检测:
1 #include <stdio.h>
2
3 int main() {
4 int num = 1; // 在内存中表示为 0x00000001 (4字节)
5
6 // 将int指针强制转换为char指针,这样就可以访问到num的第一个字节
7 char *byte_ptr = (char *)#
8
9 // 如果第一个字节是1,说明低位字节存放在了低地址,是小端
10 if (*byte_ptr == 1) {
11 printf("This machine is Little-Endian.\n");
12 } else { // 否则第一个字节是0,是大端
13 printf("This machine is Big-Endian.\n");
14 }
15
16 return 0;
17 }