【C语言】自定义类型:结构体,联合,枚举(下)

前言;上一期我们侧重讲了一个非常重要的自定义类型结构体,这一期我们来说说另外两种自定义类型:联合,和枚举。

传送门:自定义类型:结构体,联合,枚举(上)

文章目录

  • 一,联合体
    • 1,什么是联合体
    • 2,联合体的特点
    • 3,相同成员的结构体和联合体对比
    • 4,联合体大小的计算
    • 5,判断大小端存储
  • 二,枚举类型
    • 1,什么是枚举

一,联合体

1,什么是联合体

在前面我们已经学过一种自定义类型结构体,那么另外两种自定义类型也必然与结构体有相似之处所以我们类比来学习。

与结构体一样联合体也由一个或多个成员构成,这些成员同样也可以是不同的类型。
那到底联合体与结构体有什么本质上的区别呢?我们通过一个例子来观察:

#include <stdio.h> 
//联合类型的声明 
union Un 
{ char c; int i; 
};
int main() 
{ //联合变量的定义 union Un un = {0}; //计算连个变量的⼤⼩ printf("%d\n", sizeof(un)); return 0; 
}

由于联合体的定义,创建,初始化均与前面的结构体相同在这里就不再赘述!
各位读者觉得运行结果会是什么呢?
我们这里直接给出运行结果:

在这里插入图片描述
结果为什么是4呢?

在联合体内部定义了一个char和一个int类型的数据内存再怎么说也因该是5吧,可这里打印出来的大小为什么是4呢?

带着这个疑问我们将联合体nu的地址打印出来看看能不能回答我们的疑问:

#include <stdio.h> 
//联合类型的声明 
union Un 
{ char c; int i; 
};
int main() 
{ //联合变量的定义 union Un un = {0}; //计算连个变量的⼤⼩ printf("%d\n", sizeof(un)); printf("%p\n",&un.c);printf("%p\n",&un.i);printf("%p\n",&un);return 0; 
}

我们将结果打印出来:
在这里插入图片描述

不看不知道一看吓一跳,无论是&un.c成员的地址还是&un.i的地址以及&un的地址都是一样的,这已经很明显的说明了一个问题就是,联合体内部的成员共用一块内存空间!

可能会有人疑惑说为什么他们3个的地址一样就能说明他们是共用同一块内存空间呢?

首先计算机将一个大内存分成若干个内存单元,每一个内存单元就是一个字节。而在指针(1)我们谈到计算机是需要进行编址的,如何进行编址呢?是以每一个字节,(注意是字节)来进行编址。所以每一个字节的空间都有它自己的地址编号。
回头看上面的代码,无论是&un.c成员的地址还是&un.i的地址以及&un的地址都相同,这就说明了他们位于同一个字节的空间里面。如下图
在这里插入图片描述

这就可以解决我们上面的疑惑了,联合体不像结构体一样每个成员都有自己独立的空间,联合体每个成员是共用一块内存空间,所以联合体也叫共用体。

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

下面运行的结果是什么呢?
我们调试起来给大家看:
在这里插入图片描述
通过调试我们发现给un.c赋值时,会修改un.i低地址处的空间,我们画出示意图:
在这里插入图片描述
当我们修改联合体内部的某一个成员时,另一个成员的值也会发生改变这就是联合体的特点。

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

先来分析两段代码:

#include<stdio.h>
struct S 
{ char c;int i; 
};
int main()
{struct S s = {0};return 0;
}

以上是结构体我们也仿照写一个联合体:

#include<stdio.h>
union Un
{ char c;int i; 
};
int main()
{union  Un un = {0};return 0;
}

我们来分析一下他们内存的占用情况:
在这里插入图片描述
通过上面对比我们也发现联合体相较于结构体能节省一定的空间。这时又会有人疑惑了说那联合体的大小怎么去计算呢?下面我们就来看看联合体是怎么计算大小的。

4,联合体大小的计算

1.首先联合的大小至少是最大成员的大小。
2. 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

我们来看代码:

#include <stdio.h> 
union Un1 
{  char c[5]; int i;  
}; 
union Un2 
{ short c[7]; int i;
}; 
int main() 
{ //下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2)); return 0; }

我们给出运行结果:
在这里插入图片描述
那为什么是8和16呢?

这就要说到内存对齐了,其实联合体也是有内存对齐的,在Un1这个结构体中我们首先定义了一个char类型的数组大小为5,再加上一个int类型的i所以该联合体的大小至少也是5个字节,但是联合体的总大小必须是最大对齐数的整数倍,也就是4的整数倍所以将浪费3个字节变成8,此时8就为4的整数倍了。

有关于内存对齐的知识在上一篇已经详细解读过了,这里也不再过多的赘述!
传送门:自定义类型:结构体,联合,枚举(上)

同样在联合体Un2中内存至少为14个字节即7个short类型的数据,但是由于14不是最大对齐数(int类型4个字节)的整数倍,所以将浪费2个空间变成16,16就为4的整数倍了。

看到这有人就会疑惑了,说联合体到底有什么优势,有什么用处呢?
我们举个例子大家就明白了:

比如我们想要搞一个活动,需要一个礼品兑换清单,礼品兑换清单中包括三种商品,图书,杯子,衬衫。且每一件商品都有相同的的描述商品的信息库存量,价格,和其他特有信息比如:

  1. 图书——书名,页数,作者
  2. 杯子——设计
  3. 衬衫——设计,颜色,尺寸

那要如何来设计呢?

struct gift_list
{//相同的属性int tock_number;//商品存量double price;//价格//图书的属性char title[10];//书名int page;//页数char auther[10];//作者//杯子的属性char design[20];//设计//衬衫的属性char design[20];//设计char colors;//颜色int size;//尺寸
};

上面我们创建了一个结构体,结构体包含了这些信息在使用的时候也非常的方便只需要创建一个结构体变量,在用.操作符访问每个成员即可,但有一点就是我们在结构体写的其实都是大家的属性,比如我们在描述图书的时候就不需要用到尺寸,颜色这些属性,那么这些空间就浪费了。

如何节省空间呢?我们不如将他们各自特有的属性放在一个联合体里面,让他们占用同一块空间。

struct gift_list 
{ int stock_number;//库存量 double price; //定价 int item_type;//商品类型 union item//描述物品各自特有属性的联合体{ struct book//描述图书特有属性的结构体{ char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 }; struct mug//描述杯子的特有属性{ char design[30];//设计 }; struct shirt//描述衬衫的特有属性{ char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ }; };
};

上面的代码这样写有什么好处呢?其实我们将这些商品的特有属性放在一个联合体里面之后他们就占用的同一个空间,在描述图书的时候另外两个商品的性质也会被改变,同时又节省了空间。这就是联合体的优势

5,判断大小端存储

写一个程序来判断当前编译器是大端存储还是,小端存储。

  1. 大端存储是将数据的高位字节存储在内存的低地址处。
  2. 小端存储是将数据的低位字节存储在内存的低地址处。

以1为例,首先我们来分析一下大端存储1和小端存储1有什么区别:
在这里插入图片描述
通过画图观察我们发现大端和小端存储1的区别就是其第一个字节存放的是0还是1,所以我们只要拿到第一个字节的数据,看看是0还是1即可判断是大端存储还是小端存储:

#include<stdio.h>
union Un
{char a;int i;
};
int main()
{union Un un={0};un.i=1;//将整型i里面放入数据1if(un.a==1)//拿出第一个字节看看是1还是0{printf("小端");//是1说明低位放在地址 小端}else{printf("大端");//是0说明高位放到低地址 大端}return 0;
}

在这里插入图片描述
通过运行结果可知vs中的数据都是通过小端来存储的。

以上就是有关联合的内存,下面来介绍枚举类型

二,枚举类型

1,什么是枚举

枚举顾名思义就是一一列举,就像是我们在中学里学概论的时候碰到一些简单的题会将每一种可能情况都一一列举出来,这其实就是枚举。
那什么值可以一一列举呢?比如
一周的星期可以列举
一年的月份可以列举

这些数据就可以使用枚举来列举:

enum Day//eunm为枚举类型的关键字 这里以列举星期举例 
{Mon, Tues, Wed, Thur=4,//赋初值 初始化Fri=5, //赋初值 初始化Sat=6, Sun   //最后一个成员是没有逗号的这里要注意
};
int main()
{enum Day day1=Mon;enum Day day2=Tues;enum Day day3=Wed;printf("%d %d %d",day1,day2,day3);
}

在这里插入图片描述

上面定义的Day就是枚举类型,{}中的内容是枚举类型的可能取值,也叫枚举常量 。
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。
但有一点要注意就是,整数是否可以给枚举变量赋值呢?在C语言中是可以的,但是在C++是不行的的,C++的类型检查比较严格。我们换成c++给大家看看就知道了:
在这里插入图片描述
我们看到报错说无法从int转成Day说明类型不匹配是不能赋值的。

这时可能也会有人问说枚举类型到底有什么优点呢?或者我们使用#define就可以了为什么要使用枚举类型呢?

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

好了以上就是本章的全部内容啦!
最后感谢能够看到这里的读者,如果我的文章能够帮到你那我甚是荣幸,文章有任何问题都欢迎指出!制作不易还望给一个免费的三连,你们的支持就是我最大的动力!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/33904.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数组的介绍

1.数组的概念 数组是一组相同类型元素的集合&#xff0c;从这个描述中我们知道&#xff1a; 数组中存放1个或多个数据&#xff0c;但是数组的元素个数不为0。数组中存放的多个数据&#xff0c;类型是相同的。 数组分为一维数组和多维数组&#xff0c;多维数组一般比较多见的…

蓝桥杯 17110抓娃娃

问题描述 小明拿了 n 条线段练习抓娃娃。他将所有线段铺在数轴上&#xff0c;第 i 条线段的左端点在 li&#xff0c;右端点在 ri​。小明用 m 个区间去框这些线段&#xff0c;第 i个区间的范围是 [Li​, Ri​]。如果一个线段有 至少一半 的长度被包含在某个区间内&#xff0c;…

linux ptrace 图文详解(二) PTRACE_TRACEME 跟踪程序

目录 一、基础介绍 二、PTRACE_TRACE 实现原理 三、代码实现 四、总结 &#xff08;代码&#xff1a;linux 6.3.1&#xff0c;架构&#xff1a;arm64&#xff09; One look is worth a thousand words. —— Tess Flanders 一、基础介绍 GDB&#xff08;GNU Debugger&…

记录致远OA服务器硬盘升级过程

前言 日常使用中OA系统突然卡死&#xff0c;刷新访问进不去系统&#xff0c;ping服务器地址正常&#xff0c;立马登录服务器检查&#xff0c;一看磁盘爆了。 我大脑直接萎缩了&#xff0c;谁家OA系统配400G的空间啊&#xff0c;过我手的服务器没有50也是30台&#xff0c;还是…

电网电压暂态扰动机理与工业设备抗失压防护策略研究

什么是晃电&#xff1f; 国标GB/T 30137-2013 中定义:工频电压方均根值突然降至额定值的90%~10%&#xff0c;持续时间为10ms~1min后恢复正常的现象。Acrel8757V 晃电的原因 1.系统侧因素 短路故障&#xff1a;雷击、线路接地、设备误碰等导致电网短路&#xff0c;故障点电压…

Linux监控网络状态

一、基本介绍 1、基本语法 netstat [选项] 2、常用选项 选项 说明 -a 显示所有连接和监听的套接字&#xff08;包括TCP、UDP&#xff09;。 -t 显示 TCP 连接。 -u 显示 UDP 连接。 -l 显示正在监听的套接字&#xff08;server端&#xff09;。 -n 显示数字格式的…

UE5以插件的形式加载第三方库

之前在UE中加载第三方库的形式是以静态或者动态链接的形式加载但是不太容易复用。就想着能不能以插件的形式加载第三方库&#xff0c;这样直接把插件打包发行就可以复用了&#xff0c;之前也找过相应的教程但是很难找到比较简单易懂的教程&#xff0c;要么是比较复杂&#xff0…

Go执行当前package下的所有方法

需求&#xff1a;需要一个文件一个定时任务方法&#xff0c;当项目初始化完毕后&#xff0c;自动加载并执行这些定时任务方法 项目目录架构 main.go 初始化 package mainimport ("sql_demo/schedule" )func main() {/***** 其他初始化完毕后的操作**/// 定时任务sc…

AnyAnomaly: 基于大型视觉语言模型的零样本可定制视频异常检测

文章目录 速览摘要1. 引言2. 相关工作视频异常检测大型视觉语言模型&#xff08;LVLMs&#xff09; 3. 方法3.1. 总览3.2. 关键帧选择模块3.3. 上下文生成基于 WinCLIP 的注意力机制网格图像生成 3.4. 异常检测提示词设计异常评分 4. 实验4.1. 数据集4.2. 评估标准4.3. 结果4.4…

【AWS入门】2025 AWS亚马逊云科技账户注册指南

【AWS入门】2025 AWS亚马逊云科技账户注册指南 A Guide To Register a New account on AWS By JacksonML 0. AWS亚马逊云科技简介 Amazon Web Service(AWS) 即亚马逊云科技&#xff0c;其在全球Cloud Computing(云计算)市场占有最为重要的地位。 AWS连续13年被Gartner评为…

Spring 中 SmartInitializingSingleton 的作用和示例

一、 接口定义 SmartInitializingSingleton 是 Spring 框架提供的一个 单例 Bean 全局初始化回调接口&#xff0c;用于在 所有非延迟单例 Bean 初始化完成后 执行自定义逻辑。 核心方法&#xff1a; public interface SmartInitializingSingleton {void afterSingletonsInsta…

element tree树形结构默认展开全部

背景&#xff1a; el-tree树形结构&#xff0c;默认展开全部&#xff0c;使用属性default-expand-all【是否默认展开所有节点】&#xff1b;默认展开一级&#xff0c;设置default-expanded-keys【默认展开的节点的 key 的数组】属性值为数组。 因为我这里的数据第一级是四川【省…

大数据-spark3.5安装部署之local模式

spark&#xff0c;一个数据处理框架和计算引擎。 下载 local模式即本地模式&#xff0c;就是不需要任何其他节点资源就可以在本地执行spark代码的环境。用于练习演示。 上传解压 使用PortX将文件上传至/opt 进入/opt目录&#xff0c;创建目录module&#xff0c;解压文件至/o…

Discuz建站教程之论坛头部logo跳转链接怎么修改?

在修改头部logo跳转链接前&#xff0c;我们需要知道对应代码在哪个文件目录&#xff0c;进入宝塔或是服务器&#xff0c;找到文件&#xff1a;\template\default\common\header.htm&#xff0c;编辑器打开&#xff0c;搜索以下代码&#xff0c;大概在135行 <a href"{i…

【FreeRTOS】FreeRTOS操作系统在嵌入式单片机上裸机移植

目录 一 RTOS概述 二 FreeRTOS移植 三 FreeRTOS使用 四 附录 一 RTOS概述 先了解一些基础概念,以下内容摘自FreeRTOS官网(FreeRTOS™ - FreeRTOS™): 【1】RTOS基础知识 实时操作系统 (RTOS) 是一种体积小巧、确定性强的计算机操作系统。 RTOS 通常用于需要在严格时间限…

编译支持 RKmpp 和 RGA 的 ffmpeg 源码

一、前言 RK3588 支持VPU硬件解码&#xff0c;需要rkmpp进行调用&#xff1b;支持2D图像加速&#xff0c;需要 RGA 进行调用。 这两个库均能通过 ffmpeg-rockchip 进行间接调用&#xff0c;编译时需要开启对应的功能。 二、依赖安装 编译ffmpeg前需要编译 rkmpp 和 RGA&#xf…

深度学习基础:线性代数本质2——线性组合、张成的空间与基

目录 一、线性组合 1. 用一个有趣的角度看向量坐标 2. 如果我们选择不同的基向量会怎样&#xff1f; 3. 线性组合 4. 张成的空间 ① 二维向量的张成的空间 ② 三维向量的张成的空间​编辑 5.线性相关 6.线性无关 7. 基的定义 一、线性组合 1. 用一个有趣的角度看向量坐…

openharmony5.0中HDF驱动框架源码梳理-服务管理接口

要想大概了解一个公司&#xff0c;我们可能只需要知道它的运行逻辑即可&#xff0c;例如我们只需要知道它有财务有研发有运营等&#xff0c;财务报销、研发负责产品等即可&#xff0c;但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方…

Go语言环境搭建并执行第一个Go程序

目录 一、Windows环境搭建 二、vscode安装插件 三、运行第一个go程序 一、Windows环境搭建 下载Go&#xff1a;All releases - The Go Programming Language 这里是Windows搭建&#xff0c;选择的是windows-amd64.msi&#xff0c;也可以选择zip直接解压缩到指定目录 选择msi…

Netty基础—4.NIO的使用简介一

大纲 1.Buffer缓冲区 2.Channel通道 3.BIO编程 4.伪异步IO编程 5.改造程序以支持长连接 6.NIO三大核心组件 7.NIO服务端的创建流程 8.NIO客户端的创建流程 9.NIO优点总结 10.NIO问题总结 1.Buffer缓冲区 (1)Buffer缓冲区的作用 (2)Buffer缓冲区的4个核心概念 (3)使…