Big Endian or Little Endian 是用来描述计算机以哪种顺序存储数据,同时在网络传输中也有应用。
在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。
一、帮助理解
1、Endian来源
词源:据Jargon File记载,endian这个词来源于Jonathan Swift在1726年写的讽刺小说 "Gulliver's Travels"(《格利佛游记》)。该小说在描述Gulliver畅游小人国时碰到了如下的一个场景。在小人国里的小人因为非常小(身高6英寸)所以总是碰到一些意想不到的问题。有一次因为对水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开的争论而引发了一场战争,并形成了两支截然对立的队伍:支持从Big-End剥开的人Swift就称作Big-Endians而支持从Little-End剥开的人就称作Little-Endians……(后缀ian表明的就是支持某种观点的人:-)。Endian这个词由此而来。
1980年,Danny Cohen在其著名的论文”On Holy Wars and a Plea for Peace”中为了平息一场关于在消息中字节该以什么样的顺序进行传送的争论而引用了该词。该文中,Cohen非常形象贴切地把支持从一个消息序列的最高位开始传送的那伙人叫做Big-Endians,支持从最低位开始传送的相对应地叫做Little-Endians。此后Endian这个词便随着这篇论文而被广为采用。
如下图所示,鸡蛋一般有大小头之分,我们先将小头称为:Little-Endian,反之大头为:Big-Endian。
1)Little-endian:将低序字节存储在起始地址(低位编址)
2)Big-endian:将高序字节存储在起始地址(高位编址)
现代的计算机系统一般采用字节(Octet, 8 bit Byte)作为逻辑寻址单位。
如下图右侧,左边是16进制表示的内存地址,右边表格里已2进制存储的数据。
如果单个数据超过1Byte 则使用多个Byte去存储,我们通常用最小的内存地址表示此数据(对象)。
如上图,一个数据占用了4个Byte,那么我们通常用最小的0x20000004地址来定义这个数据。
2、MSB&LSB
MSB: 全称为Most Significant Bit,在二进制数中属于最高有效位,MSB是最高加权位,与十进制数字中最左边的一位类似。
LSB: 全称为Least Significant Bit,在二进制数中意为最低有效位,一般来说,MSB位于二进制数的最左侧,LSB位于二进制数的最右侧。
二、问题来了!
图中表示的数据到底是 0x04030201 还是 0x01020304 ?
这其实取决于Endian是哪种。
简单来说:
计算机存储数据时是从低地址开始写,
如果是Little-Endian方式存储,LSB也就是数据的最低有效位先写(比如十进制数 1234,先4再写3再写2再写1);
反之如果是Big-Endian方式存储,就从MSB也就是数据的最高有效位开始写(比如十进制数 4321,先1再写2再写3再写4);
再结合上面的问题:
当Little-Endian方式存储表示的数据为:0x04030201
当Big-Endian方式存储表示的数据为:0x01020304
三、总结:
我们可以把Endian想象成一个鸡蛋,小头-LSB-代表低位,大头-MSB-代表高位。
当为Big-Endian时,大头朝下,先写MSB再写LSB。
当位Little-Endian时,小头朝下,先写LSB再写MSB。
不同cpu默认的endian方式如下图,
四、拓展
1.为什么要注意字节序的问题呢?
你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。
但是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。
试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。
无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。
目前应该little endian是主流,因为在数据类型转换的时候(尤其是指针转换)不用考虑地址问题。
2.中端 Middle-Endian
除了big-endian和little-endian之外的多字节存储顺序就是middle-endian,比如以4个字节为例:象以3-4-1-2或者2-1-4-3这样的顺序存储的就是middle-endian。这种存储顺序偶尔会在一些小型机体系中的十进制数的压缩格式中出现。
3.网络字节序 Network Order
TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
所有网络协议都是采用大端的方式来传输数据的,所以大端方式又称为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前必须经过字节序的转换成为网络字节序后再进行传输。
4.主机序 Host Orader
它遵循Little-Endian规则。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序(Little-Endian)和网络序(Big-Endian)的转换。
参考:
1、《Lecture 22. Big Endian and Little Endian》
2、《Big Endian 和 Little Endian 详解》
3、《TCP、UDP通信 Big或Little Edian字节顺序(大小端)问题的解决》