当前位置: 首页 > news >正文

【C语言】——联合体与枚举

【C语言】——联合体与枚举

    • 一、联合体
      • 1.1、联合体类型的声明
      • 1.2、联合体的特点
      • 1.3、相同成员的结构体和联合体对比
      • 1.4、联合体的大小计算
      • 1.5、联合体的应用举例
    • 二、枚举
      • 2.1、枚举类型的声明
      • 2.2、枚举类型的优点

一、联合体

1.1、联合体类型的声明

  
  联合体也叫做共用体
  与结构体一样,联合体也是自定义类型,同样,也是由一个或多个的成员构成,这些成员类型可以相同也可以不同。
  与结构体不同的是,编译器只会为联合体中最大的成员开辟足够的内存空间。正如联合体这个名字一样,联合体的所有成员共用这一块内存空间
  这样,因为使用的是同一块内存,一个联合体成员改变,其他联合体成员也会跟着改变
  
  联合体的声明与结构体非常类似,下面我们直接看代码:

#include<stdio.h>//联合类型的声明
union Un
{char c;int i;
};int main()
{//联合变量的定义union Un un = { 0 };//计算各个变量的大小printf("%d\n", sizeof(un));return 0;
}

  
运行结果:

在这里插入图片描述

  为什么大小是 4 呢?我们一起来学习联合体的特点
  

1.2、联合体的特点

  联合体最大的特点就是所有成员共用一块内存空间,因此联合体变量的大小,至少最大成员变量的大小(因为联合体至少保证有能力存储那个成员)
  
  我们可以通过代码来理解联合体的特点
  
代码一:

#include<stdio.h>//联合类型的声明
union Un
{char c;int i;
};int main()
{//联合变量的定义union Un un = { 0 };//下面输出的结果是一样的吗?printf("%d\n", &(un.i));printf("%d\n", &(un.c));printf("%d\n", &un);
}

  
运行结果:
在这里插入图片描述

  
代码二:

#include<stdio.h>//联合类型的声明
union Un
{char c;int i;
};int main()
{//联合变量的定义union Un un = { 0 };un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);return 0;
}

运行结果:

在这里插入图片描述

  
  可以看到,代码一中,取出的三个地址都是一样的,说明成员之间共用一个内存空间
  
  至于代码二,我们发现低位字节的内容改了,我们可以通过画图来分析
  

在这里插入图片描述

  

  看到这里,不知大家有没有联想到判断大小端存储(详情请看【C语言】——数据在内存中的存储),是的,我们可以利用联合体来对判断机器是大端存储还是小端存储
  

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

  
  我们往联合体成员 i i i 中放入1,在返回联合体成员 c c c,因为 c c c c h a r char char 类型,取出的是 i i i地址最小的字节的内容,当取出值为 1,说明低位数字放低地址,为小端存储;如果为 0,说明低位数字放高地址,为大端存储
  
  

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

  
  下面,我们来对比一下相同成员的结构体和联合体的内存布局情况:

struct S
{char c;int i;
};union Un
{char c;int i;
};

  

在这里插入图片描述

  

1.4、联合体的大小计算

  
  首先,我们来看下面两种联合体的大小

#include<stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};int main()
{//下面的输出结果是什么printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}

  
运行结果:

在这里插入图片描述

  

为什么会这样呢?联合体的大小是怎么计算的呢?它满足两条规则:

  • 联合体的大小至少是其最大成员的大小
  • 当最大成员的大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍
      

图示:

在这里插入图片描述

  通过这图,就能很好地分析出上面两个联合体的大小啦

  
  

1.5、联合体的应用举例

  
  结构体的使用,最主要的是节省空间

  现在有这么一个场景:我们要举办一个活动,要上线一个礼品兑换单,兑换单中有三种商品:图书、杯子、衬衫。每一种商品都有:库存量,价格、商品类型以及和商品类型相关的其他信息

  • 图书:书面、作者、页数
  • 杯子:设计
  • 衬衫:设计、可选颜色、可选尺寸

  我们不耐心思考,直接写出一下结构

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

  
  上述的结构设计的其实很简单,用起来也很方便,但是结构汇的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单种的商品来说,只有部分属性信息是常用的,比如:
  
  商品时图书,就不需要 d e s i g n design design c o l o r s colors colors s i z e s sizes sizes
  
  所以我们就可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体这样就可以减少内存所需要的内存空间,一定程度上节省了内存。
  

struct gift_list
{//公共属性int stock_number;//库存量double price;//定价int item_type;//商品类型//特殊属性union {struct{char title[20];//书名char autor[20];//作者int num_pages;//页数}book;struct{char design[30];//设计}mug;struct{char design[30];//设计int colors;//颜色int sizes;//尺寸}shirt;};
};

  
  

二、枚举

2.1、枚举类型的声明

  C语言中枚举是什么?没错,就是你想的那个枚举
  枚举就是一一列举
  把可能的取值一 一列举
  当然,一 一列举的前提是他是有限个数
  
比如:

  • 一周的天数是有限的,7天,可以一一列举
  • 性别有:男、女、保密,可以一一列举
  • 三原色,可以一一列举
      

这些数据的表示就可以使用枚举了

enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};enum Sex//性别
{MALE,FEMALE,SECRET
};enum Coloe//颜色
{RED,GREEN,BLUE
};

  
  上述定义的 e n u m enum enum D a y Day Day e n u m enum enum S e x Sex Sex e n u m enum enum C o l o r Color Color 就是枚举类型
  而{}中的内容就是可能的取值,也叫枚举常量
  这些可能取值都是有值的,默认从 0 开始,依次往后递增 1
  
当然,我们定义枚举类型时,也可以自己给它赋初值

enum Coloe//颜色
{RED = 2,GREEN = 4,BLUE = 8
};

  
  

2.2、枚举类型的优点

  我们可以用 # d e f i n e define define 为什么还要用枚举呢?
  
相比与 # d e f i n e define define,枚举有以下优点

  • 增加代码的可读性可维护性
  • 和 # d e f i n e define define 定义的标识符相比,枚举类型有类型检查,更加严谨
  • 便于调试,预处理阶段会替换 # d e f i n e define define 定义的符号
  • 方便使用,一次可定义多个常量
  • 枚举常量是遵从作用域规则的,枚举声明在函数范围内,只能在该函数内部使用。
      

枚举类型的使用

enum Color//颜色
{RED=1,GREEN=2,BLUE=4
};enum Color clr = GREEN;//使用枚举常量给枚举变量赋值

  那我们不禁想:是否可以拿整数给枚举常量赋值呢?在 C语言 中是可以的,但是在 C++ 是不行的,C++ 的类型检查比较严格。
  
  
  
  


  好啦,本期关于联合体与枚举的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!

http://www.lryc.cn/news/342349.html

相关文章:

  • java线上问题排查之内存分析(三)
  • 中电金信:金Gien乐道 | 4月要闻速览,精彩再回顾
  • Java将文件目录转成树结构
  • 硬件工程师必读:10条职业发展黄金法则!
  • Redis是什么? 日常运维 Redis 需要注意什么 ? 怎么降低Redis 内存使用 节省内存?
  • 【Android项目】“追茶到底”项目介绍
  • 机试:进制转换问题
  • 目标检测实战(十五): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
  • github中fasttext库README官文文档翻译
  • WouoUIPagePC端实现
  • W801学习笔记十九:古诗学习应用——下
  • 类加载器ClassLoad-jdk1.8
  • 24年最新AI数字人简单混剪
  • 免备案香港主机会影响网站收录?
  • 低代码工业组态数字孪生平台
  • 代码随想录第三十八天(完全背包问题)|爬楼梯(第八期模拟笔试)|零钱兑换|完全平方数
  • idea常用知识点随记
  • (双指针) 有效三角形的个数 和为s的两个数字 三数之和 四数之和
  • 力扣每日一题114:二叉树展开为链表
  • Linux系统下使用LVM扩展逻辑卷的步骤指南
  • 探索AI编程新纪元:从零开始的智能编程之旅
  • RustGUI学习(iced)之小部件(三):如何使用下拉列表pick_list?
  • 【OceanBase诊断调优】—— Unit 迁移问题的排查方法
  • [极客大挑战 2019]PHP
  • 数据结构之跳跃表
  • 搜维尔科技:动作捕捉解决方案:销售、服务、培训和支持
  • 数据库管理-第184期 23ai:干掉MongoDB的不一定是另一个JSON数据库(20240507)
  • 刷代码随想录有感(58):二叉树的最近公共祖先
  • [开发|安卓] Android Studio 开发环境配置
  • 开发 Chrome 浏览器插件入门