C语言王国——深入自定义类型(联合体、枚举)

2024-06-21 08:36

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

目录

一、引言

二、联合体

2.1 联合体类型的声明

2.2 联合体大小的计算

2.3 联合体的实践运用

2.4 用联合体测试大小端字节序

三、枚举

3.1 枚举类型的声明

3.2 枚举类型的特点

四、总结


一、引言

我们刚学完了结构体,相信大家对自定义类型也有了些许了解,但是自定义类型中还有两个我们尚未学习,它们也急不可耐的想展现在我们面前了,所以接下来就由姜糖来带大家认识一下吧!


二、联合体

2.1 联合体类型的声明

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

所以联合体的声明和结构体类似,结构体的关键词是struct,而联合体的关键词是union。

union Un
{char a;int b;
};

2.2 联合体大小的计算

接下来我们再来探讨一下联合体的存储大小,我们用代码测试一下上面定义的联合体:

#include<stdio.h>union Un
{char a;int b;
}un;int main()
{printf("%zd", sizeof(un));return 0;
}

打印结果为:

 而如果此为结构体,考考大家前面学过的知识,应该为多少呢?        ·(答案为8)

那么我们发现,联合体和结构体的存储模式是不一样的。那么联合体是怎么存储的呢?

联合体的存储规则:

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

首先我们来了解第一句话, 正如我们前面讲到的那样,联合体的特点是所有成员共用同⼀块内存空间,所以联合体大小至少是最大成员的大小,不然当我们用到最大成员时,联合体就存储不下了。

那么接下来我们用代码看看联合体的成员是否是共用一块内存空间:

#include<stdio.h>union Un
{char a;int b;
}un;int main()
{printf("%p\n", &un);    //联合体的地址printf("%p\n", &(un.a));//联合体中a成员的地址printf("%p\n", &(un.b));//联合体中b成员的地址return 0;
}

打印结果如下:

我们发现它们的地址是一样的,我们可以确认它们都为应该地址,为了更加确定这个观点,我们来进一步测试:

#include<stdio.h>union Un
{char a;int b;
}un;int main()
{un.b = 0x11223344;un.a = 0x66;printf("%x", un.b);//看看a的改变是否影响breturn 0;
}

打印结果如下:

 所以可以更一步的确定它们共用一块内存,所以这个联合体的图为:

所以我们发现联合体比结构体更节约存储空间。

而第二句话我们该怎么理解呢?

我们用代码具体分析,比如:

union Un
{char a[6];int b;
}un;int main()
{printf("%zd", sizeof(un));return 0;
}

那么之里面的最大成员为char a[6],那么大小就为6了吗,真的是这样子的吗?那我们来看打印结果:

结果不为6而为8 ,而这里和结构体一样要对齐

所以最后6应该变成4的倍数8。 

我们也发现,其实联合体深入节约存储空间但也会存在内存浪费的现象。

2.3 联合体的实践运用

那么我们学习了联合体,那联合体有什么实际运用呢?

大家在前面的学习中也发现了联合体的节约空间的性质,那么实际运用中也和节约空间密不可分,比如生活中常见的事务的分类,那我们拿书、手机、手表来举例。

首先书、手机、手表都是一个大类——售卖的商品

手机:价格、品牌

书:价格、作者、书名

手表:价格、品牌、工艺

那么它们的结构体该怎么写呢?

struct commodity
{//公共属性int price;	//价格//私有属性char brand[10];//品牌char author[10];//作者char title[10];//书名char workmanship[10];//工艺
};

我们发现这里有很多私有属性,会被大量浪费。当这些私有属性共用一块内存空间时是不是可以大大节约空间的浪费所以接下来,我们用union联合体来优化代码:

struct commodity
{int price;	//价格union{struct{char brand[10];//品牌}phone;struct{char author[10];//作者char title[10];//书名}book;struct{char workmanship[10];//工艺char brand[10];//品牌}Wristwatch;}item;
};

这样设计结构体就能大大减少空间的浪费。 

2.4 用联合体测试大小端字节序

在学习的过程中我们也发现联合体非常适合去测试大小端的字节序,因为前面我们在测试大小端的时候我们是将同一个内存强制类型转换的,而这里我们用联合体将两个类型保存在同一个空间中就行了,代码如下:

#include<stdio.h>union Un
{int a;char b;
};int main()
{union Un un = { 0 };un.a = 1;if (un.b == 1){printf("为小端");}elseprintf("为大端");return 0;
}


三、枚举

3.1 枚举类型的声明

枚举顾名思义就是⼀⼀列举。 把可能的取值⼀⼀列举。

而我们生活中有很多可以一一列举的事务,如星期,月份,三原色等等,比如三原色的枚举: 

emun Threeprimarycolors
{red;blue;green;
};

{}中的内容是枚举类型的可能取值,也叫 枚举常量。这些可能取值都是有值的,默认从0开始,依次递增1:

比如这里的red就为0,blue就为1green就为2

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

emun Threeprimarycolors
{red;blue = 6;green;
};

这样就blue就变成了6,前面没有赋值的就按照原来的从0开始,red0,赋值后面的则继续加一,green就为7

3.2 枚举类型的特点

我们发现枚举和#define定义非常相像,那么我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

1. 增加代码的可读性和可维护性。

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

3. 便于调试,预处理阶段会删除 #define 定义的符号。

4. 使用方便,⼀次可以定义多个常量

5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。


四、总结

C语言的内容不止于此,还有更多需要我们共同发现,今天C语言的内存数据管理就到这里啦。如果姜糖有讲的不好的地方欢迎大家提出,谢谢大家,也希望大家能一键三连哦!


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



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

相关文章

从基础到高级详解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枚举的常用

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

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字典格式等。在此做个记录,方便后续用到该方