复制的方式将数据打包发送,不需要将一个4字节的数据额外进行拆分为4个单字节的数据;反之读取数据时,也可以不用将4个单字节的数据重新通过移位拼接为一个4字节数据。
1 typedef union
2 { 3 uint8 data8[4]; 4 uint32 data32; 5 }dataType; 6 7 uint32 sendData = 0x5A5AA5A5; 8 uint32 receiveData; 9 dataType commSend; 10 void main(void) 11 { 12 uint8 commData[128]; 13 //数据复制 14 commData.data32 = sendData; 15 //发送数据,字节复制,不需要再将commData.data32单独移位拆分 16 commData[0]= commSend.data8[0]; 17 commData[1]= commSend.data8[1]; 18 commData[2]= commSend.data8[2]; 19 commData[3]= commSend.data8[3]; 20 21 //读取数据时,字节复制,不需要再将已经读取到的4个单字节数据拼接 22 receiveData = commData.data32; 23 }
比如需要在同一段通信数据发送逻辑中,针对不同通信协议帧格式进行发送时,就可以这样定义数据结构。
1 typedef struct
2 {
3 uint8 head; //帧头格式相同
4 union //中间数据格式不一样
5 { 6 struct //payloadType1 7 { 8 uint8 cmd; 9 uint8 type; 10 uint8 data[5]; 11 uint8 check; 12 }msgType1; 13 14 struct //payloadType2 15 { 16 uint16 cmd; 17 uint8 data[8]; 18 uint16 check; 19 }msgType2; 20 21 uint8 data[10]; //payloadType3 22 } payloadType; 23 uint8 end; //帧尾格式相同 24 }frameType;
By the way:在使用联合体时可以注意这两个点:
1、数据大小端
使用联合体时需要注意数据大小端问题,这个取决于实际的处理器的存储方式。
大端存储就是高字节数据放在低地址。
小端存储就是高字节数据放在高地址。
如下方例子,可以知道使用的处理器的存储方式:
1 #include<stdio.h>
2 union Un
3 { 4 int i; 5 char c; 6 }; 7 union Un un; 8 9 int main() 10 { 11 un.i = 0x11223344; 12 if (un.c == 0x11) 13 { 14 printf("大端\n"); 15 } 16 else if (un.c == 0x44) 17 { 18 printf("小端\n"); 19 } 20 }
2、指针方式访问
由于在一个成员长度不同的联合体里,分配给联合体的内存大小取决于它的最大成员的大小。如果内部成员的大小相差太大,当存储长度较短的成员时,浪费的空间是相当可观的,在这种情况下,更好的方法是在联合体中存储指向不同成员的指针而不是直接存储成员本身。所有指针的长度都是相同的,这样能解决内存空间浪费的问题。
1 #include<stdio.h>
2 typedef struct
3 {
4 unsigned char a; 5 int b; 6 }stValue1; 7 8 typedef struct 9 { 10 int c; 11 unsigned char d[10]; 12 double e; 13 }stValue2; 14 15 //联合体成员定义为指针成员 16 union Un 17 { 18 stValue1 *ptrSt1; 19 stValue2 *ptrSt2; 20 }; 21 22 int main() 23 { 24 union Un *info; 25 info->ptrSt1->a = 5; 26 info->ptrSt2->e = 9.7f; 27 }
总之在实际使用联合体union过程中一句话总结:围绕成员互斥和内存共享这两个核心点去灵活设计你的数据结构。
更多技术内容和书籍资料获取敬请关注微信公众号“明解嵌入式”