为什么存在大端模式小端模式,为什么没有统一成一个标准

本文主要回顾一个计算机中的基础知识,字节序的大端模式与小端模式。

  • 什么是小端模式
  • 什么是大端模式
  • 为什么没有统一成一个标准
  • 网络字节序

为什么存在大端模式小端模式

计算机系统中内存是以字节为单位进行编址的,每个地址单元都唯一的对应着1个字节(8 bit)。这可以应对char类型数据的存储要求,因为char类型长度刚好是1个字节,但是有些类型的长度是超过1个字节的(字符串虽然是多字节的,但它本质是由一个个char类型组成的类似数组的结构而已),比如C/C++中,short类型一般是2个字节,int类型一般4个字节等。因此这里就存在着一个如何安排多个字节数据中各字节存放顺序的问题。正是因为不同的安排顺序导致了大端存储模式小端存储模式的存在。

小端模式

小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
简单的说就是低地址存低位,高地址存高位

为了方便说明,使用16进制表示这两个数,即0x12345678和0x11223344。小端模式采用以下方式存储这个两个数字:

大端模式

大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。
简单的上,就是低地址存高位,高地址存低位(跟人读写数值的顺序一样)
为了方便说明,使用16进制表示这两个数,即0x12345678和0x11223344。大端模式采用以下方式存储这个两个数字:

为什么没有统一成一个标准

一言以蔽之,这两种模式各有各的优点。

小端模式优点

  1. 内存的低地址处存放低字节,所以在强制转换数据时不需要调整字节的内容(注解:比如把int的4字节强制转换成short的2字节时,就直接把int数据存储的前两个字节给short就行,因为其前两个字节刚好就是最低的两个字节,符合转换逻辑);
  2. CPU做数值运算时从内存中依顺序依次从低位到高位取数据进行运算,直到最后刷新最高位的符号位,这样的运算方式会更高效

大端模式优点:符号位在所表示的数据的内存的第一个字节中,便于快速判断数据的正负和大小

其各自的优点就是对方的缺点,正因为两者彼此不分伯仲,再加上一些硬件厂商的坚持,因此在多字节存储顺序上始终没有一个统一的标准

网络字节序

不同的计算机使用的字节序可能不同,即有可能有的使用大端模式有的使用小端模式。那使用不同字节序模式的计算机如何进行通信呢? (目前个人PC大部分都是X86的小端模式)
TCP/IP协议隆重出场,RFC1700规定使用“大端”字节序为网络字节序,其他不使用大端的计算机要注意了,发送数据的时候必须要将自己的主机字节序转换为网络字节序(即“大端”字节序),接收到的数据再转换为自己的主机字节序。这样就与CPU、操作系统无关了,实现了网络通信的标准化。

为了程序的兼容,你会看到,程序员们每次发送和接收数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。

这么常用的操作,BSD Socket提供了封装好的转换接口,方便程序员使用。
包括从主机字节序到网络字节序的转换函数:htons、htonl;从网络字节序到主机字节序的转换函数:ntohs、ntohl。

C语言判断一个当前计算机是使用大端模式还是小端模式

下面的一段代码可以用来判断计算机是大端的还是小端的,判断的思路是确定一个多字节的值(下面使用的是4字节的整数),将其写入内存(即赋值给一个变量),然后用指针取其首地址所对应的字节(即低地址的一个字节),判断该字节存放的是高位还是低位,高位说明是Big endian,低位说明是Little endian。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main ()
{
unsigned int x = 0x12345678;
char *c = (char*)&x;
if (*c == 0x78) {
printf("Little endian");
} else {
printf("Big endian");
}
return 0;
}

其他的信息,包括那个故事,请阅读参考资料

参考资料:

字节顺序–维基百科
“字节序”是个什么鬼?
大小端存储模式精解

如果你觉得本文对你有帮助,欢迎打赏