在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。
目前在各种体系的计算机中通常采用的字节存储机制主要有两种:big-edian和little-endian。
高/地地址
我们知道数据在内存的布局(在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明)大致如下:
-----------------------
最高内存地址 0xffffffff
-----------------------
栈底
.
. 栈
.
栈顶
-----------------------
\|/
NULL (空洞)
/|\
-----------------------
堆
-----------------------
未初始化的数据
-----------------------
初始化的数据(统称数据段)
-----------------------
正文段(代码段)
-----------------------
最低内存地址 0x00000000
-----------------------
例如我们在栈上分配一个unsigned char buf[4],那么这个数组变量在栈上的布局如下:
栈底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
栈顶 (低地址)
高/低位字节
现在我们弄清了高/低地址,接着考虑高/低字节。如果我们有一个32位无符号整型0x12345678,那么高位是什么,低位又是什么呢?
其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。
字节序
高/低地址端和高/低字节都弄清了。我们来看看字节序。
字节序顾名思义字节的顺序,也就是多个字节类型的数据在内存中的存放顺序,与平台的实现有关。
前面咱们讲过字节存储机制主要有两种:
- Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
- Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
PS:网络字节序,TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况。
Big-Endian: 低地址存放高位,如下:
栈底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
栈顶 (低地址)
Little-Endian: 低地址存放低位,如下:
栈底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
栈顶 (低地址)
代码验证
在Java中的字节缓冲区中可以设置存储机制,如:
ByteBuffer buffer=ByteBuffer.allocate(4); buffer.putInt(1); System.out.println(buffer.getInt(0)); buffer.order(ByteOrder.LITTLE_ENDIAN); System.out.println(buffer.getInt(0));
因为ByteBuffer默认的存储机制是Big-Endian,所以输出结果为:
1
16777216