联合体和结构体的定义和使用几乎是一样的
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
只不过将struct 换成了 union
在使用的时候也是用 . 符号 获取成员信息。
本文主要讲一下结构体和联合体的不同
看下面的例子:
#include<stdio.h> //结构体 struct s1 { char c[11]; int i; char a; }struct_s1; //联合体 union s2 { char c[11]; int i; char a; }union_s2; //主函数 int main(){ printf("struct_s1 占用 %d ",sizeof(struct_s1)); printf("union_s2 占用 %d ",sizeof(union_s2)); return 0; }
输出结果如下:
相同类型结构体和联合体占用空间不同。
结论:
结构体变量所占内存长度是各成员占的内存长度的总和。
联合体变量所占内存长度是各最长的成员占的内存长度。
再看一个例子:
#include<stdio.h> #include<string.h> //结构体 struct s1 { char c[11]; int i; char a; }struct_s1; //联合体 union s2 { char c[11]; int i; char a; }union_s2; //主函数 int main(){ struct_s1.a = 's'; struct_s1.i = 10; strcpy(struct_s1.c,"abcdefg"); printf("struct_s1.a = %c ",struct_s1.a); printf("struct_s1.i = %d ",struct_s1.i); printf("struct_s1.c = %s ",struct_s1.c); printf("-------------------- "); union_s2.a = 's'; union_s2.i = 10; strcpy(union_s2.c,"abcdefg"); printf("union_s2.a = %c ",union_s2.a); printf("union_s2.i = %d ",union_s2.i); printf("union_s2.c = %s ",union_s2.c); return 0; }
运行结果:
结构体中的变量都能正常输出结果,但是联合体只有最后一个成员输出了正确的数据。
结论:
联合体每次只能使用一个成员。
联合体变量中起作用的成员是最后一次存放的成员,在存入新的成员后原有的成员失去了作用。
下面是一个使用结构体和联合体的例子:
1. struct的巨大作用
面对一个大型C/C++程序时,只看其对struct的使用情况我们就可以对其编写者的编程经验进行评估。因为一个大型的C/C++程序,势必要涉及一些(甚至大量)进行数据组合的结构体,这些结构体可以将原本意义属于一个整体的数据组合在一起。从某种程度上来说,会不会用struct,怎样用struct是区别一个开发人员是否具备丰富开发经历的标志。在网络协议、通信控制、嵌入式系统的C/C++编程中,我们经常要传送的不是简单的字节流(char型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体。经验不足的开发人员往往将所有需要传送的内容依顺序保存在char型数组中,通过指针偏移的方法传送网络报文等信息。这样做编程复杂,易出错,而且一旦控制方式及通信协议有所变化,程序就要进行非常细致的修改。一个有经验的开发者则灵活运用结构体,举一个例子,假设网络或控制协议中需要传送三种报文,其格式分别为packetA、packetB、packetC:
优秀的程序设计者这样设计传送的报文:
在进行报文传送时,直接传送struct CommuPacket一个整体。
假设发送函数的原形如下:
// pSendData:发送字节流的首地址,iLen:要发送的长度
Send(char * pSendData, unsigned int iLen);
发送方可以直接进行如下调用发送struct CommuPacket的一个实例sendCommuPacket:
Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );
假设接收函数的原形如下:
// pRecvData:发送字节流的首地址,iLen:要接收的长度
//返回值:实际接收到的字节数
unsigned int Recv(char * pRecvData, unsigned int iLen);
接收方可以直接进行如下调用将接收到的数据保存在struct CommuPacket的一个实例
recvCommuPacket中:Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );
接着判断报文类型进行相应处理:switch(recvCommuPacket. iPacketType) { case PACKET_A: … //A类报文处理 break; case PACKET_B: … //B类报文处理 break; case PACKET_C: … //C类报文处理 break; }以上程序中最值得注意的是
Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );
Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );
中的强制类型转换:(char *)&sendCommuPacket、(char *)&recvCommuPacket,先取地址,再转化为char型指针,这样就可以直接利用处理字节流的函数。利用这种强制类型转化,我们还可以方便程序的编写,例如要对sendCommuPacket所处内存初始化为0,可以这样调用标准库函数memset():
memset((char *)&sendCommuPacket,0, sizeof(CommuPacket));