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

相关文章

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、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Kotlin 枚举类使用举例

《Kotlin枚举类使用举例》枚举类(EnumClasses)是Kotlin中用于定义固定集合值的特殊类,它表示一组命名的常量,每个枚举常量都是该类的单例实例,接下来通过本文给大家介绍Kotl... 目录一、编程枚举类核心概念二、基础语法与特性1. 基本定义2. 带参数的枚举3. 实现接口4. 内置属性三、