不同CPU存取顺序不同,PowerPC系列采用Big Endian(BE)方式存储,而x86系列则采用Little Endian(LE)方式。
对于0x12345678,LE架构CPU存取
LE架构CPU存取:
BE架构CPU存取:
注:在LE系统中,通过htonl,htons仅转换字节序,每个字节中的比特序没有变化,读取还是从高到低,如下:
应用举例
1. IPv4地址
如下192.168.10.1在LE系统中通过inet_addr(“192.168.10.1”)作为整数为:0x10aa8c0
2. IPv6地址
2013:4::119在内存中作为128位整数如下:
通过:inet_pton(AF_INET6,saddr6, &addr6)转换后的
3. LE系统检查IP地址比特位是否置位,如128位的IPV6地址:
逻辑IPV6地址128位:
LE系统中按LE格式存储16字节如下:
LE系统中按BE格式存储16字节如下:
Linux内核对IP地址测试比特位函数addr_bit_set实现如下:
/*
* testbit
*/
#ifdefined(__LITTLE_ENDIAN)
# defineBITOP_BE32_SWIZZLE (0x1F & ~7)
#else
# defineBITOP_BE32_SWIZZLE 0
#endif
static__inline__ __be32 addr_bit_set(void*token, intfn_bit)
{
__be32*addr = token;
/*
* Here,
* 1<< ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
* is optimized version of
* htonl(1<< ((~fn_bit)&0x1F))
* See include/asm-generic/bitops/le.h.
*/
return(__force __be32)(1 << ((~fn_bit ^BITOP_BE32_SWIZZLE) & 0x1f)) &
addr[fn_bit >> 5];
}
注释中说明了关于掩码位的计算,下面更进一步解释一下
令:
M1 = 1 << ((~fn_bit ^BITOP_BE32_SWIZZLE) & 0x1f);
M2 = htonl(1<<((~fn_bit)&0x1F));
M1与M2等价原因:
以4字节为例,BE与LE比特序也是倒过来的,测试IP地址第0位,相当于测试BE格式的第31位,即有:~fn_bit &0x1f,等价于31-fn_bit。测试IP地址第31位,相当于测试BE格式的第0位,即时~fn_big&0xlf,等价于31-fn_bit。1<<((~fn_bit)&0x1F)这个是LE下32位掩码,所以转成BE格式掩码,即htonl(1<<((~fn_bit)&0x1F))。
htonl就是把字节0与3对调,字节1与2对调。所以~fn_bit ^BITOP_BE32_SWIZZLE把(~fn_bit)低3位不变,高2位按位取反,即与BITOP_BE32_SWIZZLE=11000B即可实现。
注:异或运算,与1异或相当取反,与0异或保持不变。
下面举列来说明一下:
如:对0位BE格式的IP测试,即fn_bit=0,参上图我们可以看出,BE格式的掩码应该是:
即在LE系统中为0x80,存储如下:
为什么在IP协议中,LE系统不把比特序转换BE后给网卡?
LE系统网卡本身有这样转换功能,网卡把数据按比特发到网络上时,每一字节是从高比特位开始读取,这样产生的就是BE格式的比特序列。
http://blog.csdn.net/lovekatherine/article/details/1564731