C语言 联合和枚举

目录

  • 1. 联合体
    • 1.1 联合体类型的声明
    • 1.2 联合体变量的创建
    • 1.3 联合体的特点
    • 1.4 联合体在内存中的存储
    • 1.5 联合体使用举例
  • 2. 枚举类型
    • 2.1 枚举类型的声明
    • 2.2 枚举变量的创建和初始化
    • 2.3 枚举类型的大小
    • 2.4 枚举类型的优点


正文开始

上次我们通过《C语言 结构体详解》学习了结构体的相关知识,今天我们来学习一下结构体的亲戚联合枚举,它们同结构体一样,都是C语言中的自定义类型,由一个或多个成员构成。因为本文所讲内容与结构体有很多相似之处,所以先学习结构体再食用本文更佳呦~

1. 联合体

1.1 联合体类型的声明

联合体的声明和结构体的声明类似:

union Un_name
{
	member-list;
};

其中:

  • union用来声明这是一个联合体
  • Un_name是联合体名
  • member-list为成员列表

1.2 联合体变量的创建

#include <stdio.h>

//联合体类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合变量的定义
	union Un un = { 0 };
	un.i = 3;
	un.c = 'a';
	return 0;
}

联合体变量的创建以及初始化等与结构体基本相同,这里不再赘述。

1.3 联合体的特点

联合体的声明与结构体基本相同,那两者有什么区别呢?我们都知道结构体在内存中的存储符合内存对齐规则,这样做的好处就是增强了性能,但是却浪费了空间。而联合体主打一个节省空间,原因如下:

  • 联合体成员共用一块内存(所以联合体又叫共用体)
  • 联合体大小至少为最大成员的大小,这样才能确保能放下所有数据

我们写个代码验证一下:

# include <stdio.h>

union Un
{
	char c;
	int i;
};

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

运行结果:
在这里插入图片描述
由此我们验证了,联合体成员共用一块内存。

1.4 联合体在内存中的存储

联合体成员共用一块内存,那他们究竟是怎么存储的呢?

  • 联合体的大小至少是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
  • 由于联合体成员共用同一块内存,所以一般独立使用各个联合体成员

例如:

#include <stdio.h>

union Un1
{
	char c[5];
	int i;
};

union Un2
{
	short c[7];
	int i;
};

int main()
{
	printf("Un1 -> %zd\n", sizeof(union Un1));
	printf("Un2 -> %zd\n", sizeof(union Un2));
	return 0;
}

在内存中的存储情况如下:
在这里插入图片描述

上图可以看出,整个联合体的大小满足两个条件:

  • 至少是最大成员的大小
  • 大小要对齐到最大对齐数的整数倍。例如 Un1 最大的对齐数是4,所以总大小补齐为8;Un2 最大的对齐数是4,所以总大小补齐为16

运行验证一下:
在这里插入图片描述

1.5 联合体使用举例

假如我们需要记录图书、杯子、衬衫三种商品的数据,每一种商品都有:库存量、价格、商品类型和一些其他信息:

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

如果我们使用结构体书写:

struct Product
{
	//共有属性
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	//特有属性
	char title[20];//书名
	char author[20];//作者
	int num_page;//页数
	
	char design[30];//设计
	int colors;//颜色
	int sizes;//尺寸
};

这样写似乎没有什么问题,但一个结构中包含了所有商品的各种属性,当我们描述图书的时候,就用不上设计、颜色和设计,这样就使得结构体的大小偏大,比较浪费内存。所以我们可以使用联合体书写:

struct Product
{
	//共有属性
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	union
	{
		struct
		{
			char title[20];//书名
			char author[20];//作者
			int num_page;//页数
		}book;//图书
		struct
		{
			char design[30];//设计
		}mug;//杯子
		struct
		{
			char design[30];//设计
			int colors;//颜色
			int sizes;//尺寸
		}shirt;//衬衫
	}item;
};

这样就相当于把三种商品的特有属性共存在一块内存中,使用时也相互独立,这样保证了正常使用,也能够节省空间。

2. 枚举类型

枚举,顾名思义就是一个一个列举,比如我们现实生活中:

  • 星期一到定期日可以列举
  • 性别可以列举
  • 月份可以列举

2.1 枚举类型的声明

枚举类型的声明与结构体类似:

enum Enum_name
{
	value1,
	value2,
	value3,
	//...
};
  • 使用关键字enum来声明枚举类型
  • Enum_name为枚举名
  • {}中的内容为枚举类型的可能取值,称作枚举常量。
  • 枚举常量之间由,隔开
  • 枚举常量都是有初始值的,默认从0开始,步长为1依次递增。
  • 给定枚举常量的值,就类似于#define定义标识符,只不过#define是在预处理阶段完成的,枚举类型是在编译阶段完成的

例如:

enum Color
{
	RED,//0
	GREEN,//1
	BLUE//2
};

我们也在声明枚举类型时赋值:

enum Color1
{
	RED=3,//3
	GREEN,//4
	BLUE//5
};

enum Color2
{
	RED=3,//3
	GREEN=5,//5
	BLUE=7//7
};

enum Color3
{
	RED,//0
	GREEN=3,//3
	BLUE//4
};

对于枚举类型的理解:
声明一个枚举,就是定义了一种类型,这种类型的可能取值就是枚举常量的值

2.2 枚举变量的创建和初始化

枚举变量的创建和初始化与结构体类似,这里只做演示,详情不再赘述。

enum Color
{
	RED,//0
	GREEN,//1
	BLUE//2
};

int main()
{
	enum Color red = 0;//等同于RED
	//定义了一个类型为 enum Color 的枚举变量red
	//变量 red 的值为0,也就是RED
	return 0;
}

2.3 枚举类型的大小

枚举是一种数据类型,它的可能取值就使枚举常量的值,枚举常量本质都是整型,也就是说,不管是枚举类型,还是枚举变量,亦或是枚举常量,它们的大小都与整型相同,都是4个字节,下面我们验证一下:

#include <stdio.h>

enum Color
{
	RED,
	GREEN,
	BLUE
};

int main()
{
	enum Color red;
	printf("%d\n", sizeof(enum Color));//枚举类型
	printf("%d\n", sizeof(RED));//枚举常量
	printf("%d\n", sizeof(GREEN));//枚举常量
	printf("%d\n", sizeof(BLUE));//枚举常量
	printf("%d\n", sizeof(red));//枚举变量
	return 0;
}

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

2.4 枚举类型的优点

有的人可能会想到,既然都是定义常量,那为什么不用#define呢?

因为枚举有以下优点:

  • 枚举将标识符集中起来,不像是#define那样分散开,增加了代码的可读性和可维护性
  • 枚举类型定义的标识符有类型检查(是枚举类型),更为严谨,而#define没有(直接替换)
  • 便与调试,预处理阶段会删除#define定义的符号
  • 使用方便,一次可以定义多个常量
  • 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用,而#define定义的标识符是全部都直接替换


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/591537.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的饭店外卖平台的设计与实现

项目描述 这是一款基于SpringBoot的饭店外卖平台的系统 模块描述 用户端 登录 首页 商家信息 点餐 菜品列表 下单 订单列表 账号下单列表 个人中心 个人资料 修改信息 评论管理 评论菜品 查看评论 打赏骑手 打赏骑手 管理员 登录 菜品管理 修改 下架 订单列表 下单记录 菜品管理…

领域驱动设计(DDD)笔记(一)基本概念

文章链接 领域驱动设计&#xff08;DDD&#xff09;笔记&#xff08;一&#xff09;基本概念-CSDN博客领域驱动设计&#xff08;DDD&#xff09;笔记&#xff08;二&#xff09;代码组织原则-CSDN博客领域驱动设计&#xff08;DDD&#xff09;笔记&#xff08;三&#xff09;后…

C#知识|事件集中响应,多个按钮关联同一事件(实例练习)

哈喽&#xff0c;你好&#xff0c;我是雷工&#xff01; 本节学习窗体Controls集合、控件事件的统一关联及如何优化重复代码。 01 事件集中响应 原理&#xff1a;就是相同的控件&#xff0c;可以关联同一个事件响应方法。 02 示例演示 2.1、示例功能 该示例实现窗体中选择…

光伏光热热泵系统(PVT)介绍

伏光热PVT热泵是一种主动利用太阳辐射能的有效方式&#xff0c;其不仅能够进行光伏发电&#xff0c;还能够利用少量的电能提高热能的品位。太阳能PVT热泵除具有发电和制热的功能外&#xff0c;还可以制冷&#xff0c;其产生的冷能可用于夏季建筑室内温度的调节。 与此同时&…

STM32单片机wifi云平台+温度+烟雾+火焰+短信+蜂鸣器 源程序原理图

目录 1. 整体设计 2. 液晶显示 3. Ds18b20温度传感器 4. Mq2烟雾传感器 5. 火焰传感器传感器 6. 蜂鸣器驱动控制 7. 按键 8. Gsm短信模块 9. Esp8266wifi模块 10、源代码 11、资料内容 资料下载地址&#xff1a;STM32单片机wi…

Adobe-Premiere-CEP 扩展 入门-视频剪辑-去气口插件-Silence Remover

短视频&#xff0c;这两年比较火&#xff0c;不要再问为什么用Premiere&#xff0c;非常难用&#xff0c;为什么不用某影&#xff0c;某些国内软件非常接地气简单&#xff0c;又例如某音资深的视频短编辑就很好用了。。。 Premiere二次开发调试难&#xff0c;不如自己搞个cons…

展开说说:Android Fragment完全解析-卷三

本文章分析了Fragment的管理器FragmentManager、事务FragmentTransaction 、以及完整的声明周期和动态加载Fragment的原理解析。 1、Fragment管理器 FragmentManager 类负责在应用的 fragment 上执行一些操作&#xff0c;如添加、移除或替换操作&#xff0c;以及将操作添加到…

介绍BCD码

BCD码&#xff08;Binary-Coded Decimal‎&#xff09;&#xff0c;用4位 二进制数 来表示1位 十进制数 中的0~9这10个数码&#xff0c;是一种二进制的数字编码形式&#xff0c;用 二进制编码的十进制 代码。 BCD码这种编码形式利用了四个位元来储存一个十进制的数码&#xff0…

关于莫比乌斯变换属性梳理

文章目录 一、说明二、多视角看莫比乌斯变换2.1 从几何角度2.2 复分析中的莫比乌斯变换2.3 莫比乌斯变换运算组合2.4 莫比乌斯变换的不动点2.5 三个点决定一个莫比乌斯变换2.6 交叉比2.7 莫比乌斯变换的逆变换 三 莫比乌斯变换性质证明3.1 证明1&#xff1a;莫比乌斯变换将圆变…

最新SpringBoot项目地方废物回收机构管理系统

采用技术 最新SpringBoot项目地方废物回收机构管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 登录页面 后端管理员 管理员首页 员工管理 设…

微星主板安装双系统不能进入Ubuntu的解决办法

在微星主板的台式机上面依次安装了Windows11和Ubuntu22.04。在Ubuntu安装完成后重启&#xff0c;没有出现系统选择界面&#xff0c;直接进入了Windows11。怎么解决&#xff1f;方法如下&#xff1a; &#xff08;1&#xff09;正常安装Windows11 &#xff08;2&#xff09;安…

基于php+mysql+html简单图书管理系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

需求规格说明书编制书(word原件)

1 范围 1.1 系统概述 1.2 文档概述 1.3 术语及缩略语 2 引用文档 3 需求 3.1 要求的状态和方式 3.2 系统能力需求 3.3 系统外部接口需求 3.3.1 管理接口 3.3.2 业务接口 3.4 系统内部接口需求 3.5 系统内部数据需求 3.6 适应性需求 3.7 安全性需求 3.8 保密性需…

# IDEA 复制项目 Module 出现 不同模块下的 Product 类报错

IDEA 复制项目 Module 出现 不同模块下的 Product 类报错 我们 用 IDEA 复制项目 Module 出现 不同模块下的 Product 类报错&#xff0c;发现复制的 module 名称没有改变或者 java 文件夹后面还有原项目 source root 字样&#xff0c;maven 父子项目没有标识等问题。 解决方法…

二叉树四种遍历方法

目录 树基本概念 二叉树二叉树的五种形态特殊二叉树二叉链表创建四种遍历方法代码实现 树 树是一个n个节点的有限集&#xff0c;当n0时称之为空树 基本概念 性质 1. 树的定义是递归的&#xff0c;树的定义中又用到了自身 2. 树的根节点没有前驱&#xff0c;除根结点外&#x…

开了个新店!

大家好&#xff0c;我是麦鸽。 一言难尽&#xff0c;五一之前&#xff0c;把大A里的钱都提出来了&#xff0c;又整了一个新的小店。熟悉我的老读者应该都知道&#xff0c;我主业是做嵌入式的&#xff0c;后面慢慢转了技术管理的路线。平时也搞点副业&#xff0c;餐饮店就是其中…

关于链表带环问题为什么要用快慢指针

判断链表是否带环 题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连…

定制开发AI名片商城AI导购系统:引领营销自动化的新时代

在数字营销日新月异的今天&#xff0c;一个革命性的工具——定制开发AI名片商城AI导购系统&#xff0c;正逐渐崭露头角&#xff0c;成为企业私域运营中的得力助手。它不仅仅是一个营销工具&#xff0c;更是一个拥有强大营销自动化能力和先进算法技术的在线助理&#xff0c;为企…

Ubuntu 域名解析出现暂时性错误

Ubuntu 域名解析出现暂时性错误 问题描述解决方案 问题描述 由于在Ubuntu系统里面经常切换网络导致&#xff0c;系统一直处于有线网络连接但是没网状态&#xff0c;尝试ping网络也无法完成&#xff0c;尝试了很多方法均不能解决 解决方案 点击”虚拟机“ 按照要求设置好即可…

Java | Spring框架 | BeanFactory与ApplicationContext

Spring容器&#xff1a;BeanFactory与ApplicationContext Spring容器是Spring框架的核心&#xff0c;负责实例化、配置和组装Bean。 Spring容器有两种主要类型&#xff1a;BeanFactory和ApplicationContext。 一、BeanFactory 基本功能&#xff1a;BeanFactory是Spring框架…