端序包括字节序和位序。
结论a:
struct定义字段按照从内存低位地址到高位地址排列。
简单回顾大小尾:
大尾序符合人们习惯,数的高位分布在内存中的低位地址。
小尾序相反。
字节序主要用在网络通讯。
使用场景:当本地的多字节整数如short或long,需要发送到网络。
不同的设备可能使用不同的字节序(包括大尾序、小尾序等,具体取决于CPU类型),导致多字节整形变量在内存中排列的顺序不同, 直接发送到网络,导致字节序不同的设备发送同样的内容产生不同的效果。所以网络发送前,整形变量需要进行一次转换,转换为网络序(网络序为大尾序)。
比如,实际值0x12345678,在大尾序中,内存从低位地址到高排地址列顺序为0x12345678,小尾序中从低到高为0x78563412。它们都是以字节为基本单元的。
除了字节序,还有位序。如果只是从事上层开发,应该不用关注到位序。
不过如果刚看过linux中tcp.h、ip.h的定义并需要使用的同学,可能还有疑问。
位序和字节序一样,大尾在内存中的排列符合人类习惯,在内存中高位数值分布在低位地址(或许不应该这么叫),小尾正好相反。
结论b:
对于发送同一个字节,大尾和小尾在内存中分布是不同的,但是能达到同样的效果,底层在发送时,发送的内容取决于字节的实际值,和字节内的内存中顺序无关。
下面给出linux的ip.h文件中的一部分:
struct iphdr {
#ifdef __LITTLE_ENDIAN_BITFIELD
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__be32 saddr;
__be32 daddr;
};
先给出结论:
结论c:
开发者可以不用关心位序相关的内容,直接使用相关字段即可。
下面简单验证上面的结论。
已知struct中的字段排列为由低位到高位,令 version=1,ihl=2,
在大尾设备上,根据上面结构体,内存中的内容为:0001 0002,实际值为0001 0002
在小尾设备上,如果version字段在前,由结论a,得到内存中的内容为:1000 2000,实际值为0002 1000
在小尾设备上,根据上面结构体,内存中的内容为:2000 1000,实际值为0001 0002
可以看出,第三组与第一组的实际值吻合,由结论b,两个字节内容相同即可产生相同的报文,得知验证成功。