在各类计算机体系结构中,对于字节(byte)、字(bit)的存储机制有所不一样,于是,引起了计算机通讯领域中一个很重要的问题,即通讯双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传输。若是不达成一致的规则,通讯双方将没法进行正确的编/译码,从而致使通讯失败。markdown
1980年,丹尼·寇恩(Danny Cohen)在其著名的论文“关于圣战与和平的呼吁(On Holy Wars and a Plea for Peace)”中,为了平息一场关于在消息中,字节该以什么样的顺序进行传输的争论而引用了该词。该文中,Cohen很是形象贴切地,把支持从一个消息序列的最高位开始传输的那伙人叫作Big-Endians,支持从最低位开始传输的相应地叫作Little-Endians。此后,Endian这个词便随着这篇论文而被广为采用。网络
首先,明确一点,我们接触到的物理单元最小都是字节;所以,不管是Big-Endian,仍是Little-Endian,都是针对多个字节的序列而言的;固然,在通讯领域中,这里每每是bit,不过原理也是相似的,稍后咱们会分析。函数
对于字节序列的存储格式,目前有两大阵营,那就是摩托罗拉(Motorola)的PowerPC系列和Intel的x86系列CPU。PowerPC采用Big-Endian方式存储数据,而x86系列则采用Little-Endian方式存储数据。那么究竟什么是Big-Endian,什么又是Little-Endian呢?oop
举个例子,若是咱们将0x1234abcd写入到以0x0000开始的内存中,则结果为:spa
address | Big-Endian | Little-Endian |
---|---|---|
0x0000 | 0x12 | 0xcd |
0x0001 | 0x34 | 0xab |
0x0002 | 0xab | 0x34 |
0x0003 | 0xcd | 0x12 |
注:每一个地址存一个字节,2位16进制数是一个字节(0xFF = 11111111)。.net
为何要注意字节序的问题呢?你可能会这么问。固然,若是你写的程序只在单机环境下面运行,而且不和别人的程序打交道,那么你彻底能够忽略字节序的存在。翻译
可是,若是你的程序要和别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则惟一采用Big-Endian方式来存储数据。设计
试想,若是你用C/C++语言在x86平台(x86平台采用Little-Endian存储数据)下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x1234abcd来举例,你的程序传递给别人的一个数据,将指向0x1234abcd的指针传给了JAVA程序,因为JAVA采起Big-Endian方式存储数据,很天然的它会将你的数据翻译为0xcdab3412。什么?居然变成另一个数字了?就是这种结果。所以,在你的C程序传给JAVA程序以前有必要进行字节序的转换工做。指针
无独有偶,全部网络协议也都是采用Big-Endian的方式来传输数据的。因此有时候咱们也会把Big-Endian方式称之为网络字节序。当两台采用不一样字节序的主机通讯时,在发送数据以前都必须通过字节序的转换,成为网络字节序后再进行传输。code
目前应该Little-Endian是主流,由于在数据类型转换的时候(尤为是指针转换)不用考虑地址问题。
Big-Endian:
基于其存储特色,符号位在所表示的数据的内存的第一个字节中,便于快速判断数据的正负和大小(CPU作数值运算时从内存中依顺序依次从低位地址到高位地址取数据进行运算,大端就会最早拿到数据的(高字节的)符号位)。
Little-Endian
基于其存储特色,内存的低地址处存放低字节,因此在强制转换数据时不须要调整字节的内容(好比,把int---4字节强制转换成short---2字节,就能够直接把int数据存储的前两个字节给short就行,由于其前两个字节恰好就是最低的两个字节,符合转换逻辑;另外CPU作数值运算时,从内存中依顺序依次从低位地址到高位地址取数据进行运算,开始只管取值,最后刷新最高位地址的符号位就行,这样的运算方式会更高效一些)。
由于两种模式各有优势,存在“你有我无,你无我有”的特色,因此造就了不一样的硬件厂商基于不一样的效率(角度)考虑,有了不一样的硬件设计支持,最终造成了计算机各个相关领域目前并无采用统一的字节序,没有统一标准的现状。
目前咱们常见的CPU PowerPC、IBM是大端模式,x86是小端模式。ARM既能够工做在大端模式,也能够工做在小端模式,通常ARM都默认是小端模式。通常通信协议都采用的是大端模式。
另外,常见文件的字节序以下:
文件类型 | 字节序 |
---|---|
BMP | Little-Endian |
GIF | Little-Endian |
JPEG | Big-Endian |
RTF | Little-Endian |
Adobe PS | Bit-Endian |
但是有朋友仍然会问,CPU存储一个字节的数据时,其字节内的8个比特之间的顺序是否也有Big-Endian和Little-Endian之分呢?或者说是否有比特序的不一样呢?
实际上,这个比特序是一样存在的。下面以数字0xB4(10110100)用图加以说明。
MSB的意思是:全称为Most Significant Bit,在二进制数中属于最高有效位,MSB是最高加权位,与十进制数字中最左边的一位相似。
LSB的意思是:全称为Least Significant Bit,在二进制数中意为最低有效位,通常来讲,MSB位于二进制树的最左侧,LSB位于二进制数的最右侧。
Big-Endian:
MSB------------------------>LSB
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
复制代码
Little-Endian:
LSB-------------------------->MSB
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
复制代码
实际上,因为CPU存储数据操做的最小单位是一个字节,其内部的比特序是什么样的,对咱们的程序来讲是一个黑盒子。也就是说,你给我一个指向0xB4这个数的指针,对于Big-Endian方式的CPU来讲,它是从左往右依次读取这个数的8个比特;而对于Little-Endian方式的CPU来讲,则正好相反,是从右往左依次读取这个数的8个比特。而咱们的程序经过这个指针访问后获得的数就是0xB4,字节内部的比特序对于程序来讲是不可见的,其实这点对于单机上的字节序来讲也是同样的。
那么可能有朋友又会问了,若是时网络传输呢?会不会出问题?是否是也要经过什么函数转换一个比特序?嗯,这个问题提的很好。假设Little-Endian方式的CPU要传给Big-Endian方式CPU一个字节的话,其自己在传输以前会在本地就读出这个8比特的数,而后再按照网络字节序的顺序来传输这8个比特,这样的话到了接收端不会出现任何问题。而假如要传输一个32比特的数的话,因为这个数在Little-Endian方存储时占了4个字节,而网络传输是以字节为单位进行的,Little-Endian方的CPU读出第一个字节后发送,实际上这个字节是原数的LSB,到了接收方反倒成了MSB,从而发生混乱。
参考资料: