从数据可视化角度理解大小端字节序问题

大小端字节序问题让人十分头疼,死记硬背并不能加深对大小端字节序的理解。但是从数据可视化的角度,就能理解大小端字节序,让人豁然开朗。

问题来源

字节序,又称端序或尾序(英语中用单词:Endianness 表示),在计算机领域中,指电脑内存中或在数字通信链路中,占用多个字节的数据的字节排列顺序。

字节的排列方式有两个通用规则:

  • 大端序(Big-Endian)将数据的低位字节存放在内存的高位地址,高位字节存放在低位地址。这种排列方式与数据用字节表示时的书写顺序一致,符合人类的阅读习惯。
  • 小端序(Little-Endian),将一个多位数的低位放在较小的地址处,高位放在较大的地址处,则称小端序。小端序与人类的阅读习惯相反,但更符合计算机读取内存的方式,因为CPU读取内存中的数据时,是从低地址向高地址方向进行读取的。

通常在计算机内部,小端序被广泛应用于现代 CPU 内部存储数据;而在其他场景,比如网络传输和文件存储则使用大端序。

从网络数据可视化看大端序

一般网络字节序为大端字节序,因为UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,网络数据解析时先收到的数据存放于低地址,否则内存的访问将是不连续的。 所以,大端字节序 = 网络字节序 = 高位放低地址。

对于整形数0x11223344,采用网络传输时,从wireshark中抓到的消息包,如下所示:

1
2
3
4
5
        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
0000 11 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

从wireshark的数据可视化角度可知,网络通信采用大端序,低地址存储高位字节,高地址存储低位字节,符合人类阅读习惯。

从内存分布可视化看小端序

操作系统内存布局

Windows在默认情况下会将高地址的2GB空间分配给内核(也可以配置为1GB),而Linux默认情况下会将高地址的1GB空间分配给内核。也就是说,应用程序只能使用剩下的2GB或3GB的地址空间,称为用户空间(User Space)。

Windows 32位程序的内存分布

图1 Windows 32位程序的内存分布

应用程序性用户空间布局

  • 堆(heap)的增长方向是向上增长,即低地址向高地址增长。
  • 栈(stack)的增长方向是向下增长,即高地址向低地址增长。

Windows 32位程序的内存分布

图2 Windows 32位程序堆栈内存分配和增长方向

应用程序中定义的变量通常在栈区存储,而栈(stack)的增长方向是向下增长,即高地址向低地址增长。因此,从如下可视化角度查看数据是合理的。

1
2
3
4
5
        F  E  D  C  B  A  9  8  7  6  5  4  3  2  1  0
0030 11 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

参考链接

  1. 什么是大端序和小端序,为什么要有字节序?,by Kevin Yan.
  2. Windows下C语言程序的内存布局,by 朴素贝叶斯.
  3. 一文弄懂大小端字节序/网络字节序,by Linux加油站.
  4. 为什么堆和栈的增长方向相反?,by 嵌入式ARM.