• 联合体union的详解


    1.概述

    联合体union的定义方式与结构体一样,但是二者有根本区别。

    在结构中各成员有各自的内存空间,一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间,一个联合变量的长度等于各成员中最长的长度。

    2.联合体长度

    在The C Programming Language里面讲述union内存分配的原话是

    1)联合体就是一个结构

    2)联合体的所有成员相对于基地址的偏移量为0

    3)此结构空间要大到总够容纳最“宽”的成员

    4)并且,其对齐方式要适合于联合体中所有类型的成员

    我的理解可以概括为两点:

    1)联合体的结构空间要足够大,要等于最长的一个结构变量的空间,但是这个最长的空间要满足以下条件:

         1.要大于等于最长的一个结构变量的空间

          2.并且要能够整除其他结构变量的数据长度,即联合体空间对其他成员的元类型要能够整除(int a[5],其元类型为int,元类型长度为4),实际上就是要取一个元类型的最小公倍数。

    这儿举例来说

    union     
    {   
        float   fuel_load;   
        char a[5];  
        int   pallets;   
    }fighter; 


    这个结构体中,各个结构变量的空间分别为float   fuel_load; 占4个字节,char a[5];占5个字节,int pallets;占4个字节。通过“3)此结构空间要大到总够容纳最“宽”的成员”这句话,我们可以认为是结构体的空间为5个字节即可,但是“其对齐方式要适合于联合体中所有类型的成员”没有满足,对于这个问题,通过上面红色字体部分可以解决。,因此联合体空间为8.8可以整除 4(float、int长度)和1(char的长度),并且8大于数组5.

    再举一个例子有助于大家理解。

    struct   aircraft 
    { 
    int   wingspan; 
    int   passengers; 
    union   
    { 
    float   fuel_load; 
    float   bomb_load; 
    int   pallets; 
    }; 
    }fighter; 

    sizeof(fighter) 是12 。int   wingspan; int   passengers;两个int型 8个字节。union中 3个都是4个字节,因此union长度为4个字节。 

    3.内存分配

    一句话:联合体变量的各个成员都是从低字节开始公用的。即:所有的成员都是从低字节开始的。

    我们先为整个union分配一个空间,这个空间大小就是上面(2)内存分配中所讲述的。

    union {
          int i;
          char x[2];
    }a;
    int main(void)
    {
       a.x[0] = 10;
       a.x[1] = 1;
       printf("%d
    ",a.i);
       return 0;
    }

    其内存如下图所示。a.x[0] 处于低字节,x[1]高字节。当调用i这个成员变量的时候,其开始地址仍然是从起始地址开始,数4个字节输出。因此为 256 + 10 = 266

    (改低地址处:0000 1010)

    程序附上:

    #include <string.h>
    #include <stdio.h>
    #include <unistd.h>
    #if 0
    typedef union data{
         float a;
         float b;
         int c;
    }data_t;
    int main(int argc ,char **argv)
    {
    
         printf("sizeof(float):%d
    sizeof(data_t):%d
    ",sizeof(float),sizeof(data_t));
         return 0;
    
    
    }
    #endif
    typedef union data{
         int i;
         char x[2];
    }data_t;
    int main(int argc ,char **argv)
    {
    
            data_t datab;
         memset(&datab,0,sizeof(datab));
         datab.x[0] = 10;
         datab.x[1] = 1;
        
            printf("sizeof(float):%d
    sizeof(int):%d
    ",sizeof(float),sizeof(int));
         printf("datab.i :%d
    ",datab.i);
         return 0;
    
    
    }

    4.附录 各个数据类型的长度

    type bytes

    int  4

    char 1

    short int 2

    bool 1

    long 4

    long long 8

    float 4

    double 8

    long double 8

     

    补充1:

    解决一下捧场网友的困惑。

    关于“有名”与“无名”联合体在结构体内所占空间的问题,其实这和是不是结构体无关,只和“有名”、“无名”有关,而且有名无名也是表象,其实是声明类型与定义变量的区别,看例子,直接打印,

    #include <stdio.h>
    struct s1{
            union u{
                    int i;
            };
            struct ss1{
                    int i;
            };
    };
    
    struct s2{
            union{
                    int i;
            };
            struct{
                    int i;
            };
    };
    
    struct s3{//the same to s2
            union su3{
                    int i;
            }su33;
            struct ss3{
                    int i;
            }ss33;
    };
    
    union su4{
            int i;
    };
    struct ss4{
            int i;
    };
    struct s4{//the same to s3
            union su4 su44;
            struct ss4 ss44;
    };
    struct s5{//the same to s1
            union su4;
            struct ss4;
    };
    
    struct s6{//the same to s1
            union{
                    int;
            };
            struct{
                    int;
            };
    };
    
    main(){
            struct s1 sVal1;
            struct s2 sVal2;
            struct s3 sVal3;
            struct s4 sVal4;
            struct s5 sVal5;
            struct s6 sVal6;
    
            printf("sVal1's size:%d
    ",sizeof(sVal1));
            printf("sVal1:%p	%d
    ",&sVal1);
    
            printf("sVal2's size:%d
    ",sizeof(sVal2));
            printf("sVal2:%p	%d
    ",&sVal2);
    
            printf("sVal3's size:%d
    ",sizeof(sVal3));
            printf("sVal3:%p	%d
    ",&sVal3);
    
            printf("sVal4's size:%d
    ",sizeof(sVal4));
            printf("sVal4:%p	%d
    ",&sVal4);
    
            printf("sVal5's size:%d
    ",sizeof(sVal5));
            printf("sVal5:%p	%d
    ",&sVal5);
    
            printf("sVal5's size:%d
    ",sizeof(sVal5));
            printf("sVal5:%p	%d
    ",&sVal5);
    }

    地址供参考,主要看size,分别为:

    0,8,8,8,0,0

    s1只有类型,没有变量,没有变量自然就没有空间占用(s5同)。

    类型就是类型,和是不是结构体、联合体无关的,你的“int i;”中i不就是个变量吗?如果换成int;结果相同(这就是s6)。

    s4和s5的做法能帮助排除干扰,将子结构体与联合体声明在外,内部直接引用,4是定义了变量,5什么都没做。

    另外,这种做法编译的时候GCC会给你在相应的行做出提示“union_with_name.c:49: 警告:没有声明任何东西”

  • 相关阅读:
    台州 OJ 3847 Mowing the Lawn 线性DP 单调队列
    洛谷 OJ P1417 烹调方案 01背包
    快速幂取模
    台州 OJ 2649 More is better 并查集
    UVa 1640
    UVa 11971
    UVa 10900
    UVa 11346
    UVa 10288
    UVa 1639
  • 原文地址:https://www.cnblogs.com/wft1990/p/6700434.html
Copyright © 2020-2023  润新知