联合体(共用体)的简单介绍

目录

概念:

联合的声明:

类比结构体:

联合体的大小:

联合的⼤⼩⾄少是最⼤成员的⼤⼩

 联合体的空间是共用的

联合体内部成员的赋值:

当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。 

 相同成员的结构体和联合体的对比:

联合体的应用:

利用联合体,判断当前机器是⼤端?还是⼩端?

什么是大端小端:

简单介绍一下:

代码演示:


概念:

联合也是一种特殊的自定义类型。

这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

联合的声明:

union un
{
 int a;
 char c;
}u;
  • union是联合的关键字,不可更改。
  • un 是联合的标签,相当于联合的名字,可以更改。
  • {}花括号内部的是联合体的成员,和结构体一样,是一个不同类型数据的集合。
  • u表示的是该联合类型创造的变量。

类比结构体:

  • 联合体类比与结构体,或者说各方各面都和结构体类似,但是有一点不同。
  • 如果将结构体比作一栋楼,那么这栋楼内有很多层住户,每一个住户都有各自的独立的空间。
  • 而相比于结构体,联合体更像是一个出租屋,里面有好几位租客,它们很多的生活空间都是共用的。

联合体的大小:

联合的⼤⼩⾄少是最⼤成员的⼤⼩

union un
{
 int a;
 char c;
}u;

int main()
{
  int ret = sizeof(u);
  printf("%d\n",ret);
  return 0;
}

从以上代码来看,int 类型的a占据了四个字节,而char 类型的c占据一个字节,那么理论上,联合体占据的总字节,应该是5个字节。

但是答案是这样吗?

并不是,这其实原理来自于联合体的特点之一:联合的⼤⼩⾄少是最⼤成员的⼤⼩。 

如上文说过,联合体好比一个出租屋,很多的生活空间都是共用的。

所以,联合体是开辟了一块大空间,让内部的成员一起使用。

 联合体的空间是共用的

又比如:

union un
{
 int a;
 char c;
}u;

int main()
{
  printf("%p\n",&u);
  printf("%p\n",&(u.a));
  printf("%p\n",&(u.c));
  return 0;
}

最终的答案是:

 这样能够证明联合体的空间是共用的。

联合体内部成员的赋值:

  • 上文讲诉了联合体的空间内部就像合租一样,是共用空间的。
  •  所以当赋予一个联合体成员数值的时候,其他的联合体成员是会被该成员的数值覆盖。

例如:

union un
{
 int a;
 char c;
}u;

int main
{
  union Un u;
  u.a = 0x11223344;
  u.c = 0x00;
  return 0;
}
  • 我们先后对成员a和成员c进行赋值。
  • 按照之前的说法,给成员c赋值,那么成员c所在的空间中的成员a的数值就会被c的数据覆盖,或者给成员a赋值,那么成员c所在空间的数据就会被a覆盖。

进行调试:

这是对int 类型的成员a进行赋值后。

随后又对char类型的成员c进行了赋值。

得到的结论如以上说法一致。,这种覆盖赋值的模式类似与共享单车。

当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。 

union un
{
 char arr[5];
 int i;
}u;

int main()
{
  printf("%d\n",sizeof(union un));
  return 0;
}

以上代码是求联合体的字节数,按照之前的说法 “ 联合的⼤⼩⾄少是最⼤成员的⼤⼩。

char arr[5]的字节大小是5,而int i 的字节大小是4,那么联合体大小一定是最大的成员的大小,也就是char arr[5]的大小,5个字节。

答案真是如此吗?

错误,这里涉及到了联合体成员内存对齐数。

具体看:http://t.csdn.cn/ONpPj

  • 注意,对齐数其实是和变量的类型和默认对齐数有关的,char类型在内存中所占据的是1个字节,而VS编译器中默认的对齐数是8
  • 而char c[5]的对齐数其实是默认对齐数 8 和 char 类型对应的1个字节中较小的那个,也就1
  • 同样,默认对齐数是8 int类型所占据的字节是4,所以int i的对齐数是4
  • 所以根据“当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍 ”得出,联合体的大小要是最大对齐数的成员的对齐数的整数倍成员i的对齐数是4,所以类型应该是4,但又根据“联合的⼤⼩⾄少是最⼤成员的⼤⼩”,而char c[5]在内存中需要5个字节,所以该联合体的大小必须大于5
  • 最后,我们只能以成员中的最大对齐数进行翻倍,得到最近的数字以此得到联合体的大小。

又列如:

union un
{
 short arr[7];
 int i;
}u;

int main()
{
  printf("%d\n",sizeof(union un));
  return 0;
}
  • 根以上原理,short arr[7] 所占据的字节是14 所以该联合体的大小至少是14
  • 而short arr[7]的对齐数是2 int i的对齐数是4,所以该联合体的大小应该是对齐数4的整数倍,所以最后的答案是16.

 相同成员的结构体和联合体的对比:

结构体
struct S
{
 char c;
 int i;
};
struct S s = {0};

联合体

union Un
{
 char c;
 int i;
};
union Un un = {0};

 

联合体的应用:

 使用联合体是可以节省空间的,举例:
比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品: 图书、杯子、衬衫每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

库存量、价格、商品类型这些其实都是公共属性,而除去这些公共属性外还有其他的一些单独属性

那么我们使用结构体来表示:

struct gift_list
{
 //公共属性
 int stock_number;//库存量
 double price; //定价
 int item_type;//商品类型
 
 //特殊属性
 char title[20];//书名
 char author[20];//作者 
 int num_pages;//⻚数
 
 char design[30];//设计
 int colors;//颜⾊
 int sizes;//尺⼨
};

而我们分别创建书、衬衫、杯子的变量时,会浪费很多空间。 

 当我们使用联合体表示时:

struct gift_list  
{
 int stock_number;//库存量
 double price; //定价
 int item_type;//商品类型
 
  union
 {
    struct
   {
     char title[20];//书名
     char author[20];//作者
     int num_pages;//⻚数
   }book;

    struct
   {
     char design[30];//设计
   }mug;

    struct
   {
    char design[30];//设计
    int colors;//颜⾊
    int sizes;//尺⼨
   }shirt;

  }item;

};

 就会节约很多空间。

打印: 创建一共结构体变量gl

gl.item.book.title
gl——最外面的结构体变量名
item——内部联合体的变量名
book ——联合体内部的某个结构体的结构体变量名
title——book这个变量所表示的结构体内部的成员名

利用联合体,判断当前机器是⼤端?还是⼩端?

什么是大端小端:

大端小端是内存存储数据的方法,而内存存储数据一般是二进制数位进行存储,所以这里便有了区分。

简单介绍一下:
int i = 1 
  • 1的十六进制数位:0x 00 00 00 01  
  • 去除前缀0x,十六进制数位从低到高是 01 00 00 00 这就是小端
  • 而十六进制数位从高到低 00 00 00 01 这就是大端。

而判断机器的是大端还是小端,则是判断这十六进制数位的最前端的字节到底是00还是01,如果是00那么是大端,如果是01那么是小端。(这里使用整型数字1的十六进制数位进行判断)

而在此时便可以利用联合体的特点。

代码演示:

int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;
}

通过提取出 int 类型的成员i 并进行赋值,而后返回char类型的成员c进行读取,因为联合体的特点,这两个成员都处在一个空间,成员c是char类型,并没有进行赋值,所以再返回后读取的其实是int类型的成员i的数据也是int类型成员i的最前端的空间数据。——(具体看联合体内部成员的赋值,这一个目录内容)

也就是可以使用以上代码,读取整型数字1再该编译器中,使用的是大端还是小端。 

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值