C/C++的结构体有一个规定,无论大端还是小端,先定义的成员一定是低字节和低位。
在大端系统中,结构体变量及其成员的存储情况如下:
.a1 .a2 .b1 .b2 .b3 .b4
bit [00:01] [02:07] [08:10] [11:14] [15:19] [20:23]
data 01 000011 100 1000 01011 0011
.a1[0:1] = 0b01(0x1);
.a2[0:5] = 0b000011(0x3);
.b1[0:2] = 0b100(0x4);
.b2[0:3] = 0b1000(0x8);
.b3[0:4] = 0b01011(0xb);
.b4[0:3] = 0b0011(0x3);
在小端系统中,各个结构体成员的存储情况如下:
.a1 .a2 .b1 .b2 .b3 .b4
bit [01:00] [07:02] [10:08] [14:11] [19:15] [23:20]
data 01 000011 100 1000 01011 0011
.a1[1:0] = 0b01(0x1);
.a2[5:0] = 0b000011(0x3);
.b1[2:0] = 0b100(0x4);
.b2[3:0] = 0b1000(0x8);
.b3[4:0] = 0b01011(0xb);
.b4[3:0] = 0b0011(0x3)
位域&大小端&以太网通信
位域可以2bit、5bit等不规则的多个bit来描述一个成员,但单通道串行通信接口只能以8bit为单位进行逐位发送,且从高bit发送还是低bit发送取决于CPU的大小端模式,大端CPU先发送bit0,小端CPU先发送bit7.
使用上文提到的结构体struct st1 data进行网络发送时会出现如下有趣现象:
大端CPU发送
发送上述数据,网络端口发送的顺序将会是(从左到右的发):01 000011 100 1000 01011 0011(为方便区分字节,同一个byte的位背景颜色相同;为方便区分结构体成员,成员间用空格隔开)。
如果接收端为大端CPU,针对每个字节的接收,收到的第一个bit放到bit0,最后一个bit放到bit7,最终收到的数据将是:bit[0:23] 01 000011 100 1000 01011 0011。如果接收端程序定义的结构体与发送端完全相同,则每个成员刚好对应上,数据解析正确。
如果接收端为小端CPU,针对每个字节的接收,收到的第一个bit放到bit7,最后一个bit放到bit0,最终收到的数据将是:bit[23:0] 1011 00111 0010 000 010000 11。如果接收端程序定义的结构体与发送端完全相同,则由于发送位序颠倒,数据已经完全紊乱。根据C/C++的规定:无论大端还是小端CPU,先定义的结构体成员一定位于低位或低字节,解析出来的数据如下:
.a1[1:0] = 0b11(0x3);
.a2[5:0] = 0b010000(0x10);
.b1[2:0] = 0b000(0x0);
.b2[3:0] = 0b0010(0x2);
.b3[4:0] = 0b00111(0x7);
.b4[3:0] = 0b1011(0xb);
和源数据相比,已经面目全非了。