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

2024-05-06 13:12

本文主要是介绍【C语言】自定义类型——联合体和枚举,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、联合体(共用体)

1.1 联合体的声明

与结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型

看一个联合体的例子:

可以看出联合体和结构体的声明很相似,只是关键字发生了改变。

1.2 联合体的特点

大家不妨猜猜这个联合体变量的大小是多少。

答案为什么是4呢?这就与联合体的特点有关了。

联合体虽然可以有很多成员,但是所有的成员都公用一块内存空间,这样联合体变量的大小至少是最大成员的大小(确保联合体变量能存下最大的成员)。

在上面的联合体中int为4字节,char为1字节,所以un这个联合体变量为4字节就可以保存任何成员

那么我们怎么确定所有成员公用一个内存空间呢?来看下面代码:

由于联合体成员公用一块内存,这就导致一个联合体变量某一刻只能保存一个成员的值。

以上面的联合体举例:如果给un.a赋值,再给un.b赋值,那么un.a的值就被un.b的值覆盖了,此时un.a可以当做不存在了。(在练习中讲内存的具体分配)

最后整体观察一下联合体和结构体的区别:

1.3 联合体大小计算

联合体大小遵循两条规则:

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

 

联合体可以存任意成员的值,但只能存一个,那我们需要哪个成员直接创建不就好了,要联合体干嘛,不是多此一举吗?实际上使用联合体可以节省内存,我们举个例子。

假设我们要搞一个活动,需要上线一个礼品兑换单,礼品单中有三种商品:图书,杯子,衬衫。

每一种商品都有:库存量,价格,商品类型和商品类型相关信息。

图书:书名,作者,页数

杯子:设计,可选颜色

衬衫:设计,可选颜色,可选尺寸

如果我们不加思考,也能写出一个结构体表示所有信息

这样的结构体很容易就能写出来,也很方便使用,但是这样的结构体包含了所有商品的信息,就会导致结构体的大小偏大,比较浪费内存。因为对于有些商品,有些属性不需要用到。

例如:商品为图书,就不需要design, colors, sizes三个属性。

所以,我们可以把公共属性单独拎出来,特殊属性使用联合体,能在一定程度上节省空间。

1.4 联合体的练习

再写练习之前,我们需要了解联合体成员的内存分配。

我们来看下面的代码:

我们能看到:我们对成员c赋值,但是只改变了较小地址的一个字节的值,其他内存中值不变。

首先,我们知道,联合体所有成员的地址都相同,都是联合体变量的较低地址;那么,在对联合体中成员赋值时,会遵循该成员的类型大小,类型大小是多少字节就修改多少字节内的值。同样,将联合体成员的值取出时也遵循成员类型大小,是多大就取多少字节的内容。用图来表示:

现在,我们可以使用这个来轻松完成一道面试题:判断当前机器是大端?还是小端?

这个题目似乎很熟悉,没错,在第一次谈大小端中我们写了一遍这道题,当时我们是这么写的:

现在我们可以通过联合体更容易写出这样的程序:

二、枚举

2.1 枚举的声明

枚举顾名思义就是——列举

把所有可能的值都列举出来。

比如,在我们日常生活中:

一周中的星期一到星期日是有限的7天,可以一一列举

性别:男,女,保密,可以一一列举

月份有12个月,可以一一列举

能描述的颜色是有限的,可以一一列举

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

 

接下来详细讲解一下如何声明一个枚举:

2.2 枚举的使用

声明完枚举类型后,我们可以创建该枚举类型的变量:

同样,我们也可以直接使用声明了的枚举类型中的枚举常量:

注意:枚举常量不能被修改值,只能在声明时赋初值时更改初值。

2.3 枚举的优点

我们学完枚举后,知道枚举就是定义常量,常量的值默认从0开始,依次增1,也可自己修改初值

但是,#define也可以定义常量,那么我们为什么要创建枚举这种类型呢?

既然枚举这种类型,那么一定有它的优点,我们来看一下:

①增加代码的可读性和可维护性

我们举个例子:

除了这个好处,枚举还有其他优点:

②和#define定义的标识符比较,枚举有类型检查,更加严谨。

③便与调试,预处理阶段会删除#define定义的符号,调试时就无法知道该值得含义。

④使用方便,一次可以定义多个常量。

⑤枚举常量遵循作用域规则,枚举声明在函数内,只能在函数内使用,而#define不遵循,会将代码中所有的标识符都删除。

这篇关于【C语言】自定义类型——联合体和枚举的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964447

相关文章

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Go语言中json操作的实现

《Go语言中json操作的实现》本文主要介绍了Go语言中的json操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录 一、jsOChina编程N 与 Go 类型对应关系️ 二、基本操作:编码与解码 三、结构体标签(Struc

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Python中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推