字节序(Endian)即字节顺序(Byte-Order),又称为端序或尾序(Endianness)。描述的是计算机如何组织字节组成对应的数字,是多字节数据存储和传输时字节的顺序, 是多字节数据在计算机内存(存储器)中存储或网络传输时(数字通信链路)各字节的存储排列顺序。
单字节的数据,比如C或Java中的char
类型的数据,是没有字节序这一说法的,因为获取它只需要读取一个字节。而多字节数据,由于存在多个字节,所在在存储和传输时可以使用不同的顺序进行操作。简单来说,字节序是指超过一个字节的数据类型在内存中存储的顺序。
字节数据的字节序跟多字节类型的数据有关,比如int
、short
、long
,对单字节byte
、char
没有影响。
在几乎所有的硬件机器上,多字节对象都被存储为连续的字节序列。
字节序分为两种排列模式,分别是大端字节序和小端字节序。
- 大端:高位字节数据存放在内存低地址处,低位字节数据存放在内存高地址处。
- 小端:高位字节数据存放在内存高地址处,低位字节数据存放在内存低地址处。
大端BE是指低地址存放最高有效字节(MSB),小端LE则是低地址存放最低有效字节(LSB)。
为什么需要注意字节序的问题呢?如果编写的程序只是在单机环境下运行,并不和其它程序打交道,那么完全可以忽略字节序的存在。如果你的程序要跟别的程序产生交互,比如C/C++语言编译的程序中数据存储顺序是跟编译平台所在的CPU相关的,Java编写的程序则采用大端BE的方式来存储数据。如果使用C/C++在x86平台下编写的程序与Java程序互通时会产生什么结果呢?比如将C程序中指向0X12345678的指针传递给Java程序,由于Java程序采取大端方式存储数据,很自然地会将传递的数据翻译为0x78563412。因此在将C程序传递给Java程序钱必须进行字节序的转换。
内存高低地址
C程序映射中内存的空间布局
- 最高内存地址
0x FFFF FFFF
- 栈区:从高内存地址往低内存地址发展,即栈底在高地址栈顶在低地址。
- 堆区:从低内存地址往高内存地址发展
- 全局区:常量和全局变量
- 代码区
- 最低内存地址:
0x 0000 0000
高低位字节数据
例如:十六进制数 0x12345678
占4个字节,分别是 0x12、0x34、0x56、0x78
,因此在该数字中0x12
属于高位字节数据,0x78
属于低位字节数据。
计算机在处理字节序的时候,并不知道什么是高位字节,什么是低位字节,它只知道按顺序读取字节,先读取第一个字节再读取第二个字节,如果是大端字节序则先读取到的就是高位字节,后读取的是低位字节。
对于字节序的处理,只有在读取的时候才必须区分字节序,其他情况都不用考虑。CPU处理器在读取外部数据时必须知道数据的字节序,才能将其转换为正确地值。当向外部设备写入数据时,是不用考虑字节序的,只需要正常写入值即可,外部设备会自己处理字节序的问题。
大端字节序
大端字节序(BE, Big Endian)又叫大端序或高端序,是将高序字节存储在内存的起始地址,内存地址低位存储着高位数据,内存地址高位存储着低位数据。
大端模式比较符合人类的阅读习惯,即高位字节在前低位字节在后,内存低位地址存放着高位数据,这是人类读写数值的方式。
内存低地址 | ... | 高位字节数据 | ... | ... | 低位字节数据 | ... | 内存高地址 |
---|---|---|---|---|---|---|---|
0x 0000 0001 | ... | 0x12 | 0x34 | 0x56 | 0x78 | ... | 0x 0000 000F |
小端字节序
小端字节序(LE, Little Endian)又叫小端序或低端序,是指内存地址低位存放低位数据,由于计算机内存数据处理是从低位开始的,因为小端模式更加符合计算机的处理方式。
内存低地址 | ... | 低位字节数据 | ... | ... | 高位字节数据 | ... | 内存高地址 |
---|---|---|---|---|---|---|---|
0x 0000 0001 | ... | 0x78 | 0x56 | 0x34 | 0x12 | ... | 0x 0000 000F |
计算机电路优先处理低位字节效率较高,因为计算机默认都是从低位开始的,所以计算机内部处理都是小端字节序。但人类习惯读写大端字节序。所以除了计算机的内部处理,其他的应用场合几乎都是大端字节序,比如网络传输和文件存储。
常见文件的字节序
文件类型 | 字节序 |
---|---|
Adobe Photoshop | Big Endian |
BMP(Windows and OS/2 Bitmap) | Little Endian |
DXF(AutoCard) | Variable |
GIF | Little Endian |
IMG(GEM Raster) | Big Endian |
JPEG | Big Endian |
FLI(Autodesk Animator) | Little Endian |
MacPaint | Big Endian |
PCX(PC Paintbrush) | Little Endian |
PostScript | NotApplicable(text!) |
POV(Persistence of Vision ray-tracer) | Not Application(text!) |
QIM(Quicktime Movies) | Little Endian(on a Mac!) |
字节序典型的应用是整数在内存中存放的方式(主机字节序)和网络传输时的顺序(网络字节序)
主机字节序
主机字节序(Host Byte Order, HBO)是指机器的字节序,有大端和小端模式,由机器的CPU处理器的处理决定,小端模式较为常见。
比如整数在内存中保存的顺序,在不同的处理器中对应不同的模式。
计算机的存储容量是以字节为最小单位来计算的,字节是存储器的最小存储单元。一个存储单元可以存储一个字节,存储单元在计算机中最小的信息单位是二进制位bit
,每8个二进制位组成一个字节byte
。
物理内存是以字节为单位进行数据存储的,每个内存存储位置都拥有一个索引或地址,每个字节可以存储一个8位数字(介于0x00和0xff之间),因此必须保留不止一个字节来存储一个更大数字。
可以将内存看成一个成大的数组,比如4GB内存是一个长度为4294967296的数组。数组的索引也就是内存地址,左边是较小的地址,右边则越来越大,直到最大值。
网络字节序
网络字节序(Network Byte Order, NBO)是TCP/IP中规定好的一种数据表示格式,网络字节序采用大端(Big Endian)排列按照从高到低的顺序存储,在网络上使用统一的网络字节顺序可以避免兼容性问题。
TCP/IP中规定好了一种数据表示格式,与具体的CPU类型、操作系统等无关,从而保证数据在不同主机之间传输时能够被正确解释。
网络序都是采用的是大端模式,因为TCP/IP协议对各层协议统一规定采用大端模式。