关于bit位域和大小端的理解

本文讨论的问题参考了两篇博文,在引用处后都做了说明,并在此表示感谢!


大小端

由于不同的计算机系统可能存在不同的大小端模式,所以不同的体系系统间通信就需要进行大小端转换。任何在不同系统间的通信信息都经过网络字节(大端)序进行传输,也就是说不管本机是什么模式,都要保证发送端传输的数据转换为网络序,接受端都要把网络序的数据转换为本地序。(bit 位域大小端转换问题 http://www.cnblogs.com/chencheng/archive/2012/06/19/2554081.html

在大端设备中,高字节数据存储在低地址,低字节数据存储在高地址;而小端设备则相反(通常intel cpu的设备都是基于小端存储的)。例如双字节数据0xF1E0,在大端设备中,0xF1存储在低地址,0xE0存储在高地址;小端设备则相反。因此,在数据传输中,通常需要将数据从本机字节序统一转换成网络字节序(网络字节序为大端)然后传输,接收方接收数据后,再将数据转换为本机字节序。由此可见,对于单字节数据,不存在大小端问题。

bit位域讨论
大小端字节序比较简单,容易理解,但如果在一个字段内存在bit变量数据,如何定义与存储呢?

引用引用另一篇博文的内容:在对struct中的成员进行分配的时候,”按排列顺序分配,先分配排在前面的”
1)big endian从高位向低位分配,
a. 对字节,是先分配低地址的字节,再分配高地址的字节。
b. 对位域,先分配most significant bits,再分配least significant bits。
1)little endian从低位向高位分配,
a. 对字节,是先分配低地址的字节,再分配高地址的字节。
b. 对位域,先分配least significant bits,再分配most significant bits。
(位域与大小端http://blog.csdn.net/qk835320459/article/details/8988175

下面举例分析,一个4字节的数据结构如下:

        /********************************************************************
         *   0               1               2               3             
         *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
         *  |A| B |  C  |   D   |    E    |     F     |           G         | 
         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *DATA:0 1 0 1 1 0 1 0 0 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 0 0 1 0 1 
         ********************************************************************/   

大端定义结构体如下:

typedef struct big_endian{
    int A:1;
    int B:2;
    int C:3;
    int D:4;
    int E:5;
    int F:6;
    int G:11;
}big_endian;

举个实际例子测试一下,对于数据0x5B 59 97 85,大端数据比较容易理解,bit序是正的。按照大端结构体定义,A~G值分别如下:

    big_endian BigEndian;
    BigEndian.A = 0x00;//0b0
    BigEndian.B = 0x02;//0b10
    BigEndian.C = 0x06;//0b110
    BigEndian.D = 0x0D;//0b1101
    BigEndian.E = 0x0C;//0b01100    
    BigEndian.F = 0x32;//0b110010
    BigEndian.G = 0x0785;//0b11110000101

然而在小端设备上,对应的小端结构体应该反过来定义(倒序定义):

typedef struct little_endian{
    int G:11;
    int F:6;
    int E:5;
    int D:4;
    int C:3;
    int B:2;
    int A:1;
}little_endian;

分别将A~G赋值(与大端对应一致)如下:

    little_endian LittleEndian;
    LittleEndian.G = 0x0785;//0b11110000101
    LittleEndian.F = 0x32;//0b110010
    LittleEndian.E = 0x0C;//0b01100
    LittleEndian.D = 0x0D;//0b1101
    LittleEndian.C = 0x06;//0b110
    LittleEndian.B = 0x02;//0b10
    LittleEndian.A = 0x00;//0b0

然后在vs2010上测试了这段代码,赋值后对应的内存如下:

由此可见LittleEndian在内存中数据为85 97 59 5b(0x5B 59 97 85),只要一次字节序转换,即可使传输数据与上面数据一致。反过来说,大端数据0x5B 59 97 85传输给小端设备接收后,在内存的数据为5B 59 97 85,未做转换时,小端设备解析为0x85 97 59 5b,转换字节序之后为0x5B 59 97 85。所以,此时需要定义两套结构体,并做字节序转换。

  • 11
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值