• 联合体(共用体)



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

    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 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));

  • 相关阅读:
    three.js
    three.js
    three.js
    反射API提供的常用类和函数
    PHP控制反转(IOC)和依赖注入(DI)
    优化思路以及优化过程
    nginx的缓存设置提高性能
    网页内容的压缩编码与传输速度优化
    nginx日志按日期自动切割脚本
    mysql数据备份
  • 原文地址:https://www.cnblogs.com/qifeng1024/p/12467864.html
Copyright © 2020-2023  润新知