C语言 联合和枚举

news2024/11/23 22:39:37

目录

  • 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定义的标识符是全部都直接替换


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解 LinkedList 及底层源码分析

LinkedList 是基于链表结构的一种 List&#xff0c;在分析 LinkedList 源码前我们先对对链表结构做一个简单的了解。 一、链表的概念 链表是由一系列非连续的节点组成的存储结构&#xff0c;简单分下类的话&#xff0c;链表又分为_单向链表和双向链表&#xff0c;而单向 / 双…

领域驱动设计(DDD)笔记(三)后端工程架构

文章链接 领域驱动设计(DDD)笔记(一)基本概念-CSDN博客领域驱动设计(DDD)笔记(二)代码组织原则-CSDN博客领域驱动设计(DDD)笔记(三)后端工程架构-CSDN博客前导 领域驱动设计(Domain Driven Design,简称DDD)是业内主导的业务工程理论。它在各中权威人士被广泛讨论…

C++ | Leetcode C++题解之第67题二进制求和

题目&#xff1a; 题解&#xff1a; class Solution { public:string addBinary(string a, string b) {string ans;reverse(a.begin(), a.end());reverse(b.begin(), b.end());int n max(a.size(), b.size()), carry 0;for (size_t i 0; i < n; i) {carry i < a.siz…

为什么 IP 地址通常以 192.168 开头?(精简版)

网络通讯的本质就是收发数据包。如果说收发数据包就跟收发快递一样。IP地址就类似于快递上填的收件地址和发件地址一样&#xff0c;路由器就充当快递员的角色&#xff0c;在这个纷繁复杂的网络世界里找到该由谁来接收这个数据包&#xff0c;所以说&#xff1a;IP地址就像快递里…

vue2项目webpack3.x打包文件分割优化加载

vue2项目webpack3.x打包文件分割优化加载 0. 项目目录和依赖信息1. 开启 gzip&#xff08;建议&#xff09;2. vue2项目配置懒加载&#xff08;建议&#xff09;3. 拆分 vendor 包注意&#xff1a;webpack3使用CommonsChunkPlugin实现 本文使用 3 种方案进行叠加优化 优先级按以…

多级留言/评论的功能实现——SpringBoot3后端篇

目录 功能描述数据库表设计后端接口设计实体类entity 完整实体类dto 封装请求数据dto 封装分页请求数据vo 请求返回数据 Controller控制层Service层接口实现类 Mapper层Mybatis 操作数据库 补充&#xff1a;返回的数据结构自动创建实体类 最近毕设做完了&#xff0c;开始来梳理…

题目:线性代数

问题描述&#xff1a; 解题思路&#xff1a; 列相乘&#xff0c;然后行相加。 注意点&#xff1a;由于元素数据范围最大为1e6&#xff0c;两个元素相乘乘积最大为1e12&#xff0c;如果元素类型为int则在乘的过程中就会爆炸&#xff0c;所以需要开long long类型。 AC代码…

深度学习500问——Chapter08:目标检测(6)

文章目录 8.3.7 RetinaNet 8.3.7 RetinaNet 研究背景 Two-Stage 检测器&#xff08;如Faster R-CNN、FPN&#xff09;效果好&#xff0c;但速度相对慢。One-Stage 检测器&#xff08;如YOLO、SSD&#xff09;速度快&#xff0c;但效果一般。 作者对one-stage检测器准确率不高…

有限单元法-编程与软件应用(崔济东、沈雪龙)【PDF下载】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

JAVA基础之线程池原理与源码简读

线程 线程是调度CPU资源的最小单位&#xff0c;线程模型分为KLT和ULT模型&#xff0c;JVM使用的KLT模型java线程与OS线程保持1:1的映射关系&#xff0c;也就是说每一个java线程对应操作系统一个线程。Java线程有以下几种生命状态&#xff1a; NEW&#xff1a;新建状态RUNNABL…

STM32——IWDG(独立看门狗)

技术笔记&#xff01; 1. IWDG&#xff08;Independent watchdog)&#xff0c;即独立看门狗 本质&#xff1a;能产生系统复位信号的计算器。 特性&#xff1a;递减计算器&#xff1b;时钟有独立的RC振荡器提供&#xff08;可在待机和停止模式下运行&#xff09;&#xff1b…

数据结构与算法---线性表

线性表 1.顺序表 需求分析 /*创建顺序表具体功能&#xff1a;初始化顺序表销毁顺序表获取顺序表元素个数输出顺序表中的内容自动扩容增 --- 插入数据&#xff08;包含了尾部添加功能&#xff09;删 --- 删除数据&#xff08;包含了尾部删除功能&#xff09;改 --- 修改数据查…

UDP编程流程(UDP客户端、服务器互发消息流程)

一、UDP编程流程 1.1、 UDP概述 UDP&#xff0c;即用户数据报协议&#xff0c;是一种面向无连接的传输层协议。相比于TCP协议&#xff0c;UDP具有以下特点&#xff1a; 速度较快&#xff1a;由于UDP不需要建立连接和进行复杂的握手过程&#xff0c;因此在传输数据时速度稍快…

【深度学习】第二门课 改善深层神经网络 Week 2 3 优化算法、超参数调试和BN及其框架

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

ASV1000视频监控平台:通过SDK接入海康网络摄像机IPC

目录 一、为何要通过SDK接入海康网络摄像机 &#xff08;一&#xff09;海康网络摄像机的SDK的功能 1、视频采集和显示 2、视频存储 3、视频回放 4、报警事件处理 5、PTZ控制 6、自定义设置 7、扩展功能 &#xff08;二&#xff09;通过SDK接入的好处&#xff08;相对…

【1小时掌握速通深度学习面试3】RNN循环神经网络

目录 12.描述循环神经网络的结构及参数更新方式&#xff0c;如何使用神经网络对序列数据建模? 13.循环神经网络为什么容易出现长期依赖问题? 14.LSTM 是如何实现长短期记忆功能的? 15.在循环神经网络中如何使用 Dropout ? 16.如何用循环神经网络实现 Seg2Seq 映射? …

2024新版Java基础从入门到精通全套教程(含视频+配套资料)

前言 Java基础是所有入门java的同学必过的一关&#xff0c;基础学习的牢固与否决定了程序员未来成就的高度。因此&#xff0c;基础学习的重要性不言而喻。 但是很多同学学习java基础知识&#xff0c;要么是学的太“基础”&#xff0c;就是只会各个知识点的简单概念和使用&…

idea 新建spring maven项目、ioc和依赖注入

文章目录 一、新建Spring-Maven项目二、在Spring-context使用IOC和依赖注入 一、新建Spring-Maven项目 在pom.xml文件中添加插件管理依赖 <build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</ver…

恶补《操作系统》4_2——王道学习笔记

4.1_5 文件存储空间管理 1、存储空间的划分与初始化 文件卷&#xff08;逻辑卷&#xff09;的概念目录区与文件区 2、几种管理方法 空闲表法&#xff1a;首位置长度&#xff0c;回收时注意修改空闲链表法&#xff08;空闲盘块链、空闲盘区链&#xff09;位示图法 成组链接法…

2024年 Java 面试八股文——Mybatis篇

目录 1. 什么是Mybatis&#xff1f; 2. 说说Mybatis的优缺点 3. Xml映射文件中&#xff0c;都有哪些标签 4. #{}和&{}有什么区别 5. Mybatis是如何进行分页的,分页插件的原理是什么 6. Mybatis是如何将sql执行结果封装为目标对象并返回的&#xff1f; 7. Mybatis是怎…