CPU体系一般以字节为单位,进行逻辑寻址。数据类型的长度大于1时,就需要考虑字节存储与传输顺序。
字节序,顾名词义,即多字节存储与传输顺序。更直接地说,就是:大于一个字节的数据类型的数据,在内存中的存放顺序(一个字节的数据,无需谈论字节序序问题)。
不同的CPU体系,对多字节数的存储机制不太相同。
因此,在通信传输中,为了保证通信双方能够正确处理,TCP/IP要求数据传输以大端字节序进行传输。
为了保证程序的可移植性,我们不能假设当前CPU体系是大端字节序?还是小端字节序?
不同CPU体系,大端/小端情况如下:
- Little endian:x86,MOS Technology 6502,Z80,VAX,PDP-11
- Big endian:Motorola 6800,Motorola 68000,PowerPC 970,System/370,SPARC(除V9外)
- 可配置:ARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC、 IA64
字节序分为两类:Big-Endian和Little-Endian。定义如下:
1、Little-Endian:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2、Big-Endian:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
3、网络字节序:按照大端字节序进行传输,以报文中的2字节“ether type”字段为例,对于ARP请求或应答的以太网帧类型来说,在网络传输时,发送的顺序是0x08,0x06。 如果当前发送实体的CPU体系是大端,则0X0806存储方式是,0X08存储在低地址,0X06存储在高地址,则从低地址向高地址方向,进行数据发送。如果当前发送实体的CPU体系是小端,则0X0806存储方式是,0X06存储在低地址,0X08存储在高地址,则从高地址向低地址方向,进行数据发送。
以unsigned int test = 0x12345678为例,分别看看在两种字节序下的存储情况:
Big-Endian,如下图:地址增长方向 → 0X12 0x34 0x56 0x78 little-endian,如下图:
地址增长方向 → 0x78 0x56 0x34 0x12 如何编程?
Linux 内核在头文件:<asm/byteorder.h>中定义了一套接口,来处理大小端字节序之间的转换,通过使用该标准接口,不再需要关心当前CPU体系是大端或小端。
接口如下:
u32 cpu_to_le32(u32);
u32 cpu_to_be32(u32);
u32 le32_to_cpu (u32);
u32 be32_to_cpu (u32);
.....
调用以上接口时,如果当前不需要转换,原样返回它们的参数;否则,转换成相应的字节序。