/*移位操作和大小端*/
无论大端还是小段,描述位操作(如,左移、右移)都遵循这个一个概念:bit0 ---> bit7是从右向左的,如下示意图:
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
并且,移位操作发生在寄存器中,和大小端无关,大小端只和存储有关。举个例子:
对于 0x1234, 不管是大端还是小端设备,寄存器中的数据都是0x1234,不会改变,位移不会影响。
大端系统字节增长方向和位域增长方向是一致的(可以参考RFC791中对ip头域的定义,以及linux kernel中对struct iphdr的定义):
byte: | 0 | 1 | 2 | 3 |
bit: 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 LSB -> MSB 从左往右
小端系统则是这样的:
byte: | 0 | 1 | 2 | 3 |
bit: 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 LSB -> MSB 从右往左
我们在代码中定义了位域,则位域都是从bit0 ---> bit7分配的(编译器都是这么定的吧...)。
比如定义了如下位域数据结构:
struct test
{
char a:1;
char b:2;
char c:3;
char d:2;
};
如上述结构体,如果定义在大端系统,则它在内存中的分布如下:
bit 7 6 5 4 3 2 1 0
d d c c c b b a == 0b abbcccdd
如果是在小端系统中定义,则它在内存中的分布如下:
bit 7 6 5 4 3 2 1 0
d d c c c b b a == 0b ddcccbba
所以对于同一个结构要在不同的大小端系统上通用,定义的时候,要分大小端来区分,参考linux kernel中对iphdr的定义:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};