在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。
字节序又分为主机字节序和网络字节序
1、主机字节序
目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Big-Endian和Little-Endian,下面先从字节序说起。
字节序,即字节在内存中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
一般CPU处理数据都以字节为单位,所以这里我们不考虑单个字节的情况,只考虑占内存多于一个字节类型的数据在内存中的存放
顺序。
其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。
大小端:
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
EG:
下面以unsigned int value = 0x12345678这个4个字节32位数据为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value,以从0x4000内存地址开始存放为例
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) -- 低位
--------------
低地址
内存地址 | 小端模式存放内容 | 大端模式存放内容 |
0x4000 | 0x78 | 0x12 |
0x4001 | 0x56 | 0x34 |
0x4002 | 0x34 | 0x56 |
0x4003 | 0x12 | 0x78 |
不同的硬件平台,不同的操作系统都有会不同的主机字节序,一般情况下如下图所示:
处理器 | 操作系统 | 字节排序 |
Alpha | 全部 | Little endian |
HP-PA | NT | Little endian |
HP-PA | UNIX | Big endian |
Intelx86 | 全部 | Little endian |
Motorola680x() | 全部 | Big endian |
MIPS | NT | Little endian |
MIPS | UNIX | Big endian |
PowerPC | NT | Little endian |
PowerPC | 非NT | Big endian |
RS/6000 | UNIX | Big endian |
SPARC | UNIX | Big endian |
IXP1200 ARM核心 | 全部 | Little endian |
2、网络字节序
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian(大端)排序方式。
由于网络字节序的存在、各系统及平台的主机字节序的不同等原因,在网络程序开发或者跨平台开发的应注意保证只使用1种字节序。所以各种编程语言的库函数中会包含以下几种字节序转换函数
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
在使用little endian的系统中,这些函数会把字节序进行转换,在使用big endian类型的系统中,这些函数会定义成空宏。