网络字节序与主机字节序
大部分IT人员在实际的开发中都很少会直接和字节序打交道。只有有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。
字节序: 顾名思义字节的顺序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
主机字节序和网络字节序
在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian,即大端模式和小端模式。
引用标准的Big-Endian和Little-Endian的定义如下:
Little-Endian: 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
Big-Endian: 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
网络字节顺序NBO(Network Byte Order)
按从高到低的顺序存储,所以Big-Endian又称网络字节序,在网络上使用统一的网络字节顺序,可以避免兼容性问题。
主机字节顺序(HBO,Host Byte Order)
不同的机器主机字节序不相同,与CPU设计有关计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。所以主机字节序存放方式有两种Big-Endian和Little-Endian。
在不同的CPU上运行不同的操作系统,字节序也是不同的,常见的参见下表。
处理器 操作系统 字节排序
Alpha 全部 Little endian
HP-PA NT Little endian
HP-PA UNIX Big endian
Intelx86 全部 Little endian <-----x86系统是小端字节序系统
Motorola680x() 全部 Big endian
MIPS NT Little endian
MIPS UNIX Big endian
PowerPC NT Little endian
PowerPC 非NT Big endian <-----PPC系统是大端字节序系统
RS/6000 UNIX Big endian
SPARC UNIX Big endian
IXP1200 ARM核心 全部 Little endian
Internet上数据以高位字节优先顺序在网络上传输,即大端字节序,所以对于在内部是以低位字节优先方式存储数据的机器(即按小端字节序存放的数据的机器,x86 系列 CPU 都是 little-endian 的字节序),在Internet上传输数据时就需要进行转换。
大端字节序和小端字节序如何在内存中存放
对大端字节序和小端字节序有一定的了解后,我们来看一下大端字节序和小端字节序是在内存中是怎样存放的。
大端字节序
在内存中,栈底是低地址位、栈顶是高地址位
例如字节序0x12345678这个16进制数在内存中以大端字节序方式存放就是这样的:
内存地址 存放内容
高地址
--------------------------
0x4003 0x78(低位)
0x4002 0x56
0x4001 0x34
0x4000 0x12(高位)
--------------------------
低地址
只需要把内存地址从左到右按照由低到高的顺序写出,那么0x12345678这个16进制数以大端字节序存放的序列就是12345678,与我们平时看到的一样,非常直观,不要考虑任何对应关系,所以大端字节序是非常符合人们平时的思维的。
小端字节序
与大端字节序在内存中的存放方式正好相反,还是以16进制数0x12345678为例,在内存中以小端字节序存放的方式是这样的:
内存地址 存放内容
高地址
--------------------------
0x4003 0x12(高位)
0x4002 0x34
0x4001 0x56
0x4000 0x78(底位)
--------------------------
低地址
将内存地址从左到右按照由低到高的顺序写出,那么0x12345678这个16进制数以小端字节序存放的序列就是78563412,与大端字节序是相反的。如果一个数0x8060在内存中占4个字节,那么它按大端字节序存放的序列就是 00 00 80 60,如果是按小端字节序的话就是60 80 00 00,所以我之前说大小端字节序未转换可能会各别字段值偏大。
总的来说大端字节序和小端字节序存储的特点就是
Little endian : 将低序字节存储在起始地址,及底地址优先存储,与人们常有存储数据思维方式相反。
Big endian : 将高序字节存储在起始地址,及高地址优先存储,符合人们常有思维。
同样在网络程序开发时或是跨平台开发时 也应该注意保证只用一种字节序不然两方的解释不一样就会产生 bug.
【用函数判断系统是Big Endian还是Little Endian】
//如果字节序为big-endian,返回true;
//反之为 little-endian,返回false
int IsMyMachineBigEndian()
{
unsigned short test = 0x1122;
unsigned char *cp = &test; //使cp指向test的地址;
return (*cp == 0x11); //如果cp所指向的地址值为0x11,则说明高字节
序0x11存放在起始地址,那么就是大端字节序,
否则就是小端字节序。
}