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