联合体(共用体)

 


 

联合体和结构体的定义和使用几乎是一样的

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\n",sizeof(struct_s1));
    printf("union_s2  占用 %d\n",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\n",struct_s1.a);
    printf("struct_s1.i = %d\n",struct_s1.i);
    printf("struct_s1.c = %s\n",struct_s1.c);

    printf("--------------------\n");

    union_s2.a = 's';
    union_s2.i = 10;
    strcpy(union_s2.c,"abcdefg");
    printf("union_s2.a = %c\n",union_s2.a);
    printf("union_s2.i = %d\n",union_s2.i);
    printf("union_s2.c = %s\n",union_s2.c);

    return 0;
}

运行结果:

 

 

结构体中的变量都能正常输出结果,但是联合体只有最后一个成员输出了正确的数据。

结论:

联合体每次只能使用一个成员。

联合体变量中起作用的成员是最后一次存放的成员,在存入新的成员后原有的成员失去了作用。

 


 

 

下面是一个使用结构体和联合体的例子:

1. struct的巨大作用

面对一个大型C/C++程序时,只看其对struct的使用情况我们就可以对其编写者的编程经验进行评估。因为一个大型的C/C++程序,势必要涉及一些(甚至大量)进行数据组合的结构体,这些结构体可以将原本意义属于一个整体的数据组合在一起。从某种程度上来说,会不会用struct,怎样用struct是区别一个开发人员是否具备丰富开发经历的标志。在网络协议、通信控制、嵌入式系统的C/C++编程中,我们经常要传送的不是简单的字节流(char型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体。经验不足的开发人员往往将所有需要传送的内容依顺序保存在char型数组中,通过指针偏移的方法传送网络报文等信息。这样做编程复杂,易出错,而且一旦控制方式及通信协议有所变化,程序就要进行非常细致的修改。一个有经验的开发者则灵活运用结构体,举一个例子,假设网络或控制协议中需要传送三种报文,其格式分别为packetA、packetB、packetC:

 

 
struct structA   
{  
    int a;  
    char b;  
};  
struct structB   
{  
    char a;  
    short b;  
};  
struct structC  
{  
    int a;  
    char b;  
    float c;  
}

 

 

优秀的程序设计者这样设计传送的报文:

 

 

struct CommuPacket  
{  
    int iPacketType;  //报文类型标志  
    union         //每次传送的是三种报文中的一种,使用union  
    {  
        struct structA packetA;  
        struct structB packetB;  
        struct structC 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));

 

posted @ 2020-03-12 11:12  祁峰_1024  阅读(515)  评论(0编辑  收藏  举报