联合体(共用体)的概念

199 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

联合体(共用体)

联合类型的定义

联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员 共用一块内存空间(因此联合也叫共用体)


//联合类型的声明
union Un
{
  	char c;
    int i ;
};
int main()
{
    union Un un;	// 联合变量的定义
    printf("%d\n",sizeeof(un));	//4
}

定义时的注意事项:成员后面记得跟分号,{}后面也要有分号,union Un这一整个是联合体类型,不能直接使用Un定义变量,或者计算联合体大小

sizeof(Un) //err

sizeof(union Un) //正解


联合的特点

联合的成员共用一块内存空间,且都从起始位置开始存放,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)


union Un
{
    int i;
    char c;
};
int main()
{
     union Un un = {0};
    printf("%p\n",&(un.i));
    printf("%p\n",&(un.c));
    printf("%p\n",&un);
}

打印结果相同地址相同。


image-20220310223038632

成员都从第一个位置开始向后存放


结构体和联合体的区别

共同点:二者的访问方式,声明方式一样且二者都有内存对齐

不同点:联合体的成员共用同一块空间 ,改变某一个成员,其他的都会发生改变,

而结构体的每个成员都有独立空间互不影响


使用联合体判断大小端

大小端:二进制的字节序在内存中存放的顺序

int a = 1;	//0x 00 00 00 01
//     低地址----->高地址
//小端存放:01 00 00 00 低字节内容放在低地址处
//大端存放:00 00 00 01 
所以只要拿出第一个字节,判断是0还是1即可知道是小端还是大端

//法1:使用char*强转,只取第一个字节
int main()
{
    int a = 1;
    char* p =(char*)&a;
    if(*p == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

优化:
int Check_DX()
{
    int a = 1;
    return *(char*)&a;
}
int main()
{
    int ret = Check_DX();
    if(ret == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
}

方法2:使用联合体

image-20220310223123280

因为共用一块内存空间,所以可以给i赋值为1,只拿c中的内容即可


union U
{
    char c;
    int i ;  
}u;	//u为全局变量
int main()
{
    u.i  = 1;
    if(u.c == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

写成函数形式:

int check_sys()
{
    union
    {
        char c;
        int i;
    }u;
    u.i = 1;
    //返回1->小端
    //返回0->大端
    return u.c;
}

联合体大小的计算

  • 联合体的大小至少是最大成员的大小

  • 但最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍

    (对齐数:成员类型的大小与编译器的对齐数(VS为8)比较,取较小值)

    (最大对齐数:联合体中所有成员的对齐数的最大值)

联合体也存在内存对齐!!!


//例子1
union Un1
{
    char c[5];
    int i;
};
int main()
{
    printf("%d\n",sizeof(union Un1));	//8
    return 0;
}

c为5个元素的char类型数组,相当于存放了5个char类型的变量,c的大小为5字节, 但是char类型大小为1byte,所以对齐数为1

i为整形变量,大小为4bit,对齐数为4

Un1成员的最大对齐数为4,最大成员大小为5

但是5不是4的倍数,浪费3个字节->联合体Un1大小为8


//例子2
union Un2
{
    short c[7];
    int i;
};
int main()
{
    printf("%d\n",sizeof(union Un2));	//16
    return 0;
}

c为7个元素的short类型数组,相当于存放了7个short类型的变量,c的大小为2*7=14字节, 但是short类型大小为为2byte 对齐数为2

i为整形变量,大小为4bit,对齐数为4

Un2成员的最大对齐数为4,最大成员大小为14,14不是4的倍数,所以浪费2个字节

->结构体Un2的大小为16byte


内存对齐

结构体,联合体存在内存对齐

位段,枚举不存在内存对齐

画位段内存布局时:画出位数 char->8位 int ->32位