/*
* test bit
*/
#if defined(__LITTLE_ENDIAN)
# define BITOP_BE32_SWIZZLE (0x1F & ~7)
#else
# define BITOP_BE32_SWIZZLE 0
#endif
static __inline__ __be32 addr_bit_set(void *token, int fn_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异或保持不变。
不仅字节存在顺序,位域也存在顺序:
#include <stdio.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <memory.h>
struct st_bits {
unsigned char s1:1;
unsigned char s2:1;
unsigned char s3:1;
unsigned char s4:1;
unsigned char s5:1;
unsigned char s6:1;
unsigned char s7:1;
unsigned char s8:1;
};
int main(int argc,char* argv[])
{
unsigned int a=0x12345678;
unsigned int b;
struct st_bits* ptr;
int i;
int addr;
struct in6_addr addr6;
int err;
char* saddr4 = "192.168.10.1";
char* saddr6 = "2013:4::119";
b = htonl(a);
ptr = (struct st_bits*) &b;
printf("Little Endian a=0x%0x\n", a);
ptr = (struct st_bits*) &a;
for(i=0; i<4; i++) {
printf("%1x %1x %1x %1x %1x %1x %1x %1x \n", ptr[i].s1, ptr[i].s2, ptr[i].s3, ptr[i].s4, ptr[i].s5, ptr[i].s6, ptr[i].s7, ptr[i].s8);
}
printf("Big Endian b=0x%0x\n", b);
ptr = (struct st_bits*) &b;
for(i=0; i<4; i++) {
printf("%1x %1x %1x %1x %1x %1x %1x %1x \n", ptr[i].s1, ptr[i].s2, ptr[i].s3, ptr[i].s4, ptr[i].s5, ptr[i].s6, ptr[i].s7, ptr[i].s8);
}
//返回的地址已经是网络字节格式,所以你无需再调用 函数htonl
addr = inet_addr(saddr4);
printf("ipv4:%s, BE addr=0x%0x\n", saddr4, addr);
ptr = (struct st_bits*) &addr;
for(i=0; i<4; i++) {
printf("%1x %1x %1x %1x %1x %1x %1x %1x \n", ptr[i].s1, ptr[i].s2, ptr[i].s3, ptr[i].s4, ptr[i].s5, ptr[i].s6, ptr[i].s7, ptr[i].s8);
}
memset(&addr6, 0, sizeof(addr6));
err = inet_pton(AF_INET6, saddr6, &addr6);
if (err < 0) {
printf("call inet_pton error, err=%d, errno=%d\n", err, errno);
}
printf("ipv6:%s\n", saddr6);
ptr = (struct st_bits*) &addr6;
for(i=0; i<16; i++) {
printf("%02x %1x %1x %1x %1x %1x %1x %1x %1x \n", addr6.s6_addr[i], ptr[i].s1, ptr[i].s2, ptr[i].s3, ptr[i].s4, ptr[i].s5, ptr[i].s6, ptr[i].s7, ptr[i].s8);
}
return 0;
}
#运行结果(LE平台)
Little Endian a=0x12345678
0 0 0 1 1 1 1 0
0 1 1 0 1 0 1 0
0 0 1 0 1 1 0 0
0 1 0 0 1 0 0 0
Big Endian b=0x78563412
0 1 0 0 1 0 0 0
0 0 1 0 1 1 0 0
0 1 1 0 1 0 1 0
0 0 0 1 1 1 1 0
ipv4:192.168.10.1, BE addr=0x10aa8c0
0 0 0 0 0 0 1 1
0 0 0 1 0 1 0 1
0 1 0 1 0 0 0 0
1 0 0 0 0 0 0 0
ipv6:2013:4::119
20 0 0 0 0 0 1 0 0
13 1 1 0 0 1 0 0 0
00 0 0 0 0 0 0 0 0
04 0 0 1 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
00 0 0 0 0 0 0 0 0
01 1 0 0 0 0 0 0 0
19 1 0 0 1 1 0 0 0