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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fu724567340/article/details/73612086

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


大小端

由于不同的计算机系统可能存在不同的大小端模式,所以不同的体系系统间通信就需要进行大小端转换。任何在不同系统间的通信信息都经过网络字节(大端)序进行传输,也就是说不管本机是什么模式,都要保证发送端传输的数据转换为网络序,接受端都要把网络序的数据转换为本地序。(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。所以,此时需要定义两套结构体,并做字节序转换。

展开阅读全文

没有更多推荐了,返回首页