【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 Day , enum Sex , enum 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 定义常量,为什么非要使用枚举?
枚举的优点:
- 增加代码的可读性和可维护性
- 和
#define定义的标识符比较枚举有类型检查,更加严谨。 - 便于调试,预处理阶段会删除
#define定义的符号 - 使用方便,一次可以定义多个常量
- 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
举个例子:实现一个简单计算器
我们就能将加减乘除设置成枚举类型,这样在主函数中进行对应的操作时就会知道就行的是哪中计算。
这里只是简单举个例子说明一下枚举的优点,具体的函数大家可以自行修改。
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. 前言 在之前的博客中介绍了自定义类型中的结构体,…...
使用Mosquitto/python3进行MQTT连接
一、简介 MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,为此,它需要一个消息中间件。 …...
JavaWeb笔记之前端开发HTML
一、引言 1.1HTML概念 网页,是网站中的一个页面,通常是网页是构成网站的基本元素,是承载各种网站应用的平台。通俗的说,网站就是由网页组成的。通常我们看到的网页都是以htm或html后缀结尾的文件,俗称 HTML文件。 …...
通过IP地址定位解决被薅羊毛问题
随着互联网的普及,线上交易和优惠活动日益增多,这也为一些不法分子提供了可乘之机。他们利用技术手段,通过大量注册账号或使用虚假IP地址进行异常操作,以获取更多的优惠或利益,这种行为被称为“薅羊毛”。对于企业和平…...
Leetcode 122 买卖股票的最佳时机 II
题意理解: 已知:一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格 如何哪个时间点买入,哪个时间点卖出,多次交易,能够收益最大化 目的:收益最大化 解题思路: 使用贪心…...
音频文件合成
音频文件合成 音频文件合成 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 简略步骤:rootrootrootroot-X99-Turbo:~/3TB$ tar --use-compress-programpigz -xvpf rk3399-android-10.git-20210201.tgz rootrootro…...
vivo 容器平台资源运营实践
作者:vivo 互联网服务器团队 - Chen Han 容器平台针对业务资源申请值偏大的运营问题,通过静态超卖和动态超卖两种技术方案,使业务资源申请值趋于合理化,提高平台资源装箱率和资源利用率。 一、背景 在Kubernetes中,容…...
ASP.NET Core面试题之Redis高频问题
🎈🎈在.NET后端开发岗位中,如今也少不了、微服务、分布式、高并发高可用相关的面试题🎈🎈 👍👍本文分享一些整理的Redis高频面试题🎉 👍👍机会都是给有准备…...
【教程】Ubuntu基本软件安装
文章目录 一、搜狗输入法安装二、百度网盘安装三、划词翻译 一、搜狗输入法安装 全网最准确的Ubuntu 20.04 安装搜狗输入法的步骤 二、百度网盘安装 百度云盘for Linux安装教程和体验 三、划词翻译 ubuntu最好用的划词翻译词典:有道词典和GoldenDict...
Jenkins 构建环境指南
目录 Delete workspace before build starts(常用) Use secret text(s) or file(s) (常用) Add timestamps to the Console Output (常用) Inspect build log for published build scans Terminate a …...
基于Go语言的HTTP路由设计与实现
在Go语言的世界里,HTTP路由是一种将HTTP请求映射到相应处理函数的技术。通过路由,我们可以确定当用户发送一个HTTP请求时,应该调用哪个函数来处理该请求。在这个过程中,我们可以使用多种方法来实现路由设计,下面我将以…...
SpringMVC01
SpringMVC 1. 学习⽬标2. 什么叫MVC?3. SpringMVC 框架概念与特点4. SpringMVC 请求流程5. Spring MVC 环境搭建6. URL 地址映射配置7. 参数绑定8. JSON 数据开发JSON普通数组步骤1:pom.xml添加依赖步骤2: 修改配置⽂件步骤3. 注解使⽤ 1. 学习⽬标 2. 什…...
基于Redis限流(aop切面+redis实现“令牌桶算法”)
令牌桶算法属于流量控制算法,在一定时间内保证一个键(key)的访问量不超过某个阈值。这里的关键是设置一个令牌桶,在某个时间段内生成一定数量的令牌,然后每次访问时从桶中获取令牌,如果桶中没有令牌&#x…...
【小白专用】php pdo方式连接sqlserver 设置方法 更新23.12.21
windows系统的拓展相对来说比较好安装,直接下载对应的dll文件,修改php.ini配置文件即可。 添加PHP对SQL SERVER的支持 1.新建PHP 文件,输入内容: <?php echo phpinfo(); ?> 2.运行后,可以查看到如下数据&…...
打开C#项目时出现“error : 找不到指定的 SDK”的错误解决方法汇总
从github上克隆项目回来,发现编译通过,我是通过一下步骤解决的: 1.到适用于 Visual Studio 的 .NET SDK 下载网址下载对应版本的.NET SDK,关闭当前VS后安装; 2.参考VS2022报错:error : 找不到指定的 SDK“…...
MIT 6.824 练习1
Hi, there! 这是一份根据 MIT 6.824(2021) 课程的第 2 课的课堂示例代码改编的 2 个 go 语言编程练习。像其他的编程作业一样,我去除了核心部分,保留了代码框架,并编写了每一步的提示 练习代码在本文的最后面 爬虫 在第一部分,…...
Git报错x509: certificate signed by unknown authority
下载报错: 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)— 如何将视频分解
前言:Hello大家好,我是小哥谈。本节课就手把手教大家如何将一幅图像转化成热力图,希望大家学习之后能够有所收获~!🌈 目录 🚀1.技术介绍 🚀2.实现代码 🚀1.技术介绍 视频是…...
Swagger2接口测试文档
目录 一、Swagger简介 1.1 Swagger是什么? 1.2 为什么要用Swagger 1.3 Swagger注解 二、Spring集成Swagger 三、测试环境配置 一、Swagger简介 1.1 Swagger是什么? Swagger 是一个开源的 API 设计和文档工具,它可以帮助开发人员更快、…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
