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

【C语言】自定义类型之联合和枚举

目录

  • 1. 前言
  • 2. 联合体
    • 2.1 联合体类型的声明
    • 2.2 联合体的特点
    • 2.3 相同成员的结构体和联合体对比
    • 2.4 联合体大小的计算
    • 2.4 判断当前机器的大小端
  • 3. 枚举
    • 3.1 枚举类型的声明
    • 3.2 枚举类型的优点
    • 3.3 枚举类型的使用

1. 前言

在之前的博客中介绍了自定义类型中的结构体,有想了解的可以点这个链接:link
今天来分享另外两种类型:联合和枚举。

2. 联合体

2.1 联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最大的成员分配足够的内存空间。
联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体

-----------------------------------------------------------------------------------------

我们举个例子来看一下:

在这里插入图片描述
我们发现在联合体中的大小占4个字节,这是为什么呢?

我们来看看它每个成员的地址
在这里插入图片描述
我们发现那三个的地址都是一样的。
改到32位平台上发现内存地址还是一样的。
在这里插入图片描述
也就是说它们共用一块空间
在这里插入图片描述

-----------------------------------------------------------------------------------------

给联合体其中⼀个成员赋值,其他成员的值也跟着变化。
在同一个时间点只能使用一个联合体成员。

2.2 联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合⾄少得有能力保存最大的那个成员)。

来看个例子

#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;
}

在这里插入图片描述
我们来看看在内存中的变换:
在这里插入图片描述
在这里插入图片描述
代码的输出,我们发现将i的第4个字节的内容修改为55了。
我们仔细分析就可以画出,un的内存布局图。
在这里插入图片描述

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

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

结构体的代码:

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

联合体的代码:

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

在这里插入图片描述
对于结构体来说就占了8个字节,浪费了3个字节,而联合体占了4个字节。

2.4 联合体大小的计算

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

举个例子:计算下面两个联合体的大小?

#include <stdio.h>union Un1
{char c[5];//5   1 8 1int i;//4       4 8 4
};union Un2
{short c[7];//14   2   8  2int i;//4         4   8  4
};int main()
{printf("%d\n", sizeof(union Un1));//8printf("%d\n", sizeof(union Un2));//16return 0;
}

在这里插入图片描述
对于Un1,char c[5],占五个字节,char类型占1个字节,对齐数默认是8,对比之后取对齐数取1。 int i,占4个字节,对齐数默认是8,对比之后取对齐数取4。所以等于5时,5不是4的倍数,就得浪费3个字节,取8。

对于Un2 ,short c[7]占14个字节,short占2个,对齐数默认是8,对比之后取对齐数取2; int i,占4个字节,对齐数默认是8,对比之后取对齐数取4。所以等于14时,14不是4的倍数,就得浪费2个字节,取16。

联合体的大小,并不是其中最大成员的大小

-----------------------------------------------------------------------------------------

使用联合体是可以节省空间的,
举例:

比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。
每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜⾊、可选尺寸

如果我们使用结构体来定义这个活动的礼物时,
在这里插入图片描述

代码如下:

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;
};

这里使用了匿名结构体,这里的书、杯子和衬衫是不能同时存在的。就按照最大的结构体内存也就是书所占的大小来开辟空间,这样其它的也能放下。

在这里插入图片描述
我们就可以选择礼物及它的成员。
在这里插入图片描述

2.4 判断当前机器的大小端

在之间博客中有说明,这里就不过多讲述,有需要的可以查看; link

在这里插入图片描述
之前所写的代码是利用指针来判断的:

int main()
{int a = 1;if (*(char*)&a == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}

在这里插入图片描述
结果显示的是小端。

-----------------------------------------------------------------------------------------

这次我们使用联合体来判断

int check_sys()
{union{char c;int i;}u;u.i = 1;return u.c;
}int main()
{if (check_sys() == 1)printf("小端\n");elseprintf("大端\n");return 0;
}

也就是来判断一下u.c存的是0还是1?
在这里插入图片描述
结果和上面一样,是小端存储
在这里插入图片描述

3. 枚举

3.1 枚举类型的声明

枚举顾名思义就是一一列举。
把可能的取值一一列举。
比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举
性别有:男、女、保密,也可以一一列举
月份有12个月,也可以一一列举
三原色,也是可以意义列举

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

enum Day
{//列出的是枚举类型的可能取值//这些列出的可能取值被称为:枚举常量Mon,Tues,Wed,Thur,Fri,Sat,Sun
};enum Sex
{MALE,FEMALE,SECRET
};enum Color//颜⾊
{RED,GREEN,BLUE
};

以上定义的 enum Dayenum Sexenum Color 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫 枚举常量
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

来看看日期的取值:
在这里插入图片描述
也就是:默认从0开始,依次递增1,一直到6。

当然在声明枚举类型的时候也可以赋初值。

enum Color//颜⾊
{RED = 2,GREEN = 4,BLUE = 8
};int main()
{printf("%d %d %d\n", RED, GREEN, BLUE);return 0;
}

在这里插入图片描述

3.2 枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:

  1. 增加代码的可读性和可维护性
  2. #define定义的标识符比较枚举有类型检查,更加严谨。
  3. 便于调试,预处理阶段会删除 #define 定义的符号
  4. 使用方便,一次可以定义多个常量
  5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用

举个例子:实现一个简单计算器
我们就能将加减乘除设置成枚举类型,这样在主函数中进行对应的操作时就会知道就行的是哪中计算。
这里只是简单举个例子说明一下枚举的优点,具体的函数大家可以自行修改。

void menu()
{printf("*********************\n");printf("*** 1.add  2.sub  ***\n");printf("*** 3.mul  4.div  ***\n");printf("*** 0.exit        ***\n");printf("*********************\n");
}enum Option
{EXIT,//0ADD,//1SUB,//2MUL,//3DIV//4
};
int Add(int a, int b)
{return a + b;
}int Sub(int a, int b)
{return a - b;
}int Mul(int a, int b)
{return a * b;
}int Div(int a, int b)
{return a / b;
}int main()
{int input = 0;int a = 0;int b = 0;do{menu();printf("请选择:");scanf("%d", &input);scanf("%d %d", &a,&b);switch (input){case ADD:Add(a, b);break;case SUB:Sub(a, b);break;case MUL:Mul(a, b);break;case DIV:Div(a, b);break;default:break;}} while (input);return 0;
}

3.3 枚举类型的使用

enum Color//颜色
{RED = 1,GREEN = 2,BLUE = 4
};int main()
{enum Color clr = GREEN;//使用枚举常量给枚举变量赋值enum Color clr2 = 2;printf("%d\n", sizeof(clr));//4return 0;
}

在这里插入图片描述

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

有错误请指出,大家一起进步!

相关文章:

【C语言】自定义类型之联合和枚举

目录 1. 前言2. 联合体2.1 联合体类型的声明2.2 联合体的特点2.3 相同成员的结构体和联合体对比2.4 联合体大小的计算2.4 判断当前机器的大小端 3. 枚举3.1 枚举类型的声明3.2 枚举类型的优点3.3 枚举类型的使用 1. 前言 在之前的博客中介绍了自定义类型中的结构体&#xff0c;…...

使用Mosquitto/python3进行MQTT连接

一、简介 MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上&#xff0c;是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议&#xff0c;为此&#xff0c;它需要一个消息中间件。 …...

JavaWeb笔记之前端开发HTML

一、引言 1.1HTML概念 网页&#xff0c;是网站中的一个页面&#xff0c;通常是网页是构成网站的基本元素&#xff0c;是承载各种网站应用的平台。通俗的说&#xff0c;网站就是由网页组成的。通常我们看到的网页都是以htm或html后缀结尾的文件&#xff0c;俗称 HTML文件。 …...

通过IP地址定位解决被薅羊毛问题

随着互联网的普及&#xff0c;线上交易和优惠活动日益增多&#xff0c;这也为一些不法分子提供了可乘之机。他们利用技术手段&#xff0c;通过大量注册账号或使用虚假IP地址进行异常操作&#xff0c;以获取更多的优惠或利益&#xff0c;这种行为被称为“薅羊毛”。对于企业和平…...

Leetcode 122 买卖股票的最佳时机 II

题意理解&#xff1a; 已知&#xff1a;一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格 如何哪个时间点买入&#xff0c;哪个时间点卖出&#xff0c;多次交易&#xff0c;能够收益最大化 目的&#xff1a;收益最大化 解题思路&#xff1a; 使用贪心…...

音频文件合成

音频文件合成 音频文件合成 http://ffmpeg.org/download.html https://blog.csdn.net/u013314786/article/details/89682800 http://www.360doc.com/content/19/0317/01/10519289_822112563.shtml https://chaijunkun.blog.csdn.net/article/details/116491526?spm1001.210…...

20231220将NanoPC-T4(RK3399)开发板的Android10的SDK按照Rockchip官方挖掘机开发板编译打包刷机之后启动跑飞

20231220将NanoPC-T4(RK3399)开发板的Android10的SDK按照Rockchip官方挖掘机开发板编译打包刷机之后启动跑飞 2023/12/20 17:19 简略步骤&#xff1a;rootrootrootroot-X99-Turbo:~/3TB$ tar --use-compress-programpigz -xvpf rk3399-android-10.git-20210201.tgz rootrootro…...

vivo 容器平台资源运营实践

作者&#xff1a;vivo 互联网服务器团队 - Chen Han 容器平台针对业务资源申请值偏大的运营问题&#xff0c;通过静态超卖和动态超卖两种技术方案&#xff0c;使业务资源申请值趋于合理化&#xff0c;提高平台资源装箱率和资源利用率。 一、背景 在Kubernetes中&#xff0c;容…...

ASP.NET Core面试题之Redis高频问题

&#x1f388;&#x1f388;在.NET后端开发岗位中&#xff0c;如今也少不了、微服务、分布式、高并发高可用相关的面试题&#x1f388;&#x1f388; &#x1f44d;&#x1f44d;本文分享一些整理的Redis高频面试题&#x1f389; &#x1f44d;&#x1f44d;机会都是给有准备…...

【教程】Ubuntu基本软件安装

文章目录 一、搜狗输入法安装二、百度网盘安装三、划词翻译 一、搜狗输入法安装 全网最准确的Ubuntu 20.04 安装搜狗输入法的步骤 二、百度网盘安装 百度云盘for Linux安装教程和体验 三、划词翻译 ubuntu最好用的划词翻译词典&#xff1a;有道词典和GoldenDict...

Jenkins 构建环境指南

目录 Delete workspace before build starts&#xff08;常用&#xff09; Use secret text(s) or file(s) &#xff08;常用&#xff09; Add timestamps to the Console Output &#xff08;常用&#xff09; Inspect build log for published build scans Terminate a …...

基于Go语言的HTTP路由设计与实现

在Go语言的世界里&#xff0c;HTTP路由是一种将HTTP请求映射到相应处理函数的技术。通过路由&#xff0c;我们可以确定当用户发送一个HTTP请求时&#xff0c;应该调用哪个函数来处理该请求。在这个过程中&#xff0c;我们可以使用多种方法来实现路由设计&#xff0c;下面我将以…...

SpringMVC01

SpringMVC 1. 学习⽬标2. 什么叫MVC&#xff1f;3. SpringMVC 框架概念与特点4. SpringMVC 请求流程5. Spring MVC 环境搭建6. URL 地址映射配置7. 参数绑定8. JSON 数据开发JSON普通数组步骤1:pom.xml添加依赖步骤2&#xff1a; 修改配置⽂件步骤3. 注解使⽤ 1. 学习⽬标 2. 什…...

基于Redis限流(aop切面+redis实现“令牌桶算法”)

令牌桶算法属于流量控制算法&#xff0c;在一定时间内保证一个键&#xff08;key&#xff09;的访问量不超过某个阈值。这里的关键是设置一个令牌桶&#xff0c;在某个时间段内生成一定数量的令牌&#xff0c;然后每次访问时从桶中获取令牌&#xff0c;如果桶中没有令牌&#x…...

【小白专用】php pdo方式连接sqlserver 设置方法 更新23.12.21

windows系统的拓展相对来说比较好安装&#xff0c;直接下载对应的dll文件&#xff0c;修改php.ini配置文件即可。 添加PHP对SQL SERVER的支持 1.新建PHP 文件&#xff0c;输入内容&#xff1a; <?php echo phpinfo(); ?> 2.运行后&#xff0c;可以查看到如下数据&…...

打开C#项目时出现“error : 找不到指定的 SDK”的错误解决方法汇总

从github上克隆项目回来&#xff0c;发现编译通过&#xff0c;我是通过一下步骤解决的&#xff1a; 1.到适用于 Visual Studio 的 .NET SDK 下载网址下载对应版本的.NET SDK&#xff0c;关闭当前VS后安装&#xff1b; 2.参考VS2022报错&#xff1a;error : 找不到指定的 SDK“…...

MIT 6.824 练习1

Hi, there! 这是一份根据 MIT 6.824(2021) 课程的第 2 课的课堂示例代码改编的 2 个 go 语言编程练习。像其他的编程作业一样&#xff0c;我去除了核心部分&#xff0c;保留了代码框架&#xff0c;并编写了每一步的提示 练习代码在本文的最后面 爬虫 在第一部分&#xff0c;…...

Git报错x509: certificate signed by unknown authority

下载报错&#xff1a; Error downloading object: model-00001-of-00008.safetensors (ed3ac49): Smudge error: Error downloading model-00001-of-00008.safetensors (ed3ac4983f682a999b0e4b6f072aad294c4fd9a7e968e90835ba5c4b466d3c7c): LFS: Get https://cdn-lfs.huggin…...

OpenCV技术应用(8)— 如何将视频分解

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本节课就手把手教大家如何将一幅图像转化成热力图&#xff0c;希望大家学习之后能够有所收获~&#xff01;&#x1f308; 目录 &#x1f680;1.技术介绍 &#x1f680;2.实现代码 &#x1f680;1.技术介绍 视频是…...

Swagger2接口测试文档

目录 一、Swagger简介 1.1 Swagger是什么&#xff1f; 1.2 为什么要用Swagger 1.3 Swagger注解 二、Spring集成Swagger 三、测试环境配置 一、Swagger简介 1.1 Swagger是什么&#xff1f; Swagger 是一个开源的 API 设计和文档工具&#xff0c;它可以帮助开发人员更快、…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...