木之陽兮 卿云烂兮

0%

大小端与序列化

进制 表示 高位 低位
十进制 4660 4 0
十六进制 0x1234 12 34
二进制 0001001000110100 0001 0100

现代的阅读/书写习惯大都是从左向右,这是大端 (Big-endian):

在低地址中存高位内容

0x001 0x002
00010010 00110100

机器中以二进制存储数数据,从低位到高位处理,这是小端 (Little-endian):

在低地址中存低位内容

0x001 0x002
00110100 00010010

以int类型的整数 65535 为例:

int 类型在内存中占4字节/32位,定义一个长度为4的数组存储序列化的内容(数组在内存空间的地址是连续的):

  • 大端
1
2
3
4
5
6
7
8
int num65535 = 0xFFFF;
// 序列化
var bytes = new byte[]{0, 0, (byte) 0xFF, (byte) 0xFF};

// 反序列化
int num = (bytes[0] & 0xFF << 24) | (bytes[1] & 0xFF << 16) | (bytes[2] & 0xFF << 8) | (bytes[3] & 0xFF)

assert num65535 == num;
  • 小端
1
2
3
4
5
6
7
8
int num61695 = 0xF0FF;
// 序列化
var bytes = new byte[]{(byte) 0xFF, (byte) 0xF0, 0, 0};

// 反序列化
int num = (bytes[0] & 0xFF) | (bytes[1] & 0xFF << 8) | (bytes[2] & 0xFF << 16) | (bytes[3] & 0xFF << 24);

assert num65535 == num;

不同的序列化框架会选择不同的模式,比如protobuf用的是小端模式,TCP/IP的网络流用的是大端模式,在读取时转换即可。