【C语言进阶】枚举与联合体

news2024/12/28 17:45:36

在这里插入图片描述
在这里插入图片描述

目录

  • 一:枚举
    • 1.1:枚举类型的定义:
    • 1.1:枚举的优点:
    • 1.2:枚举的使用:
  • 二:联合(共用体)
    • 2.1:联合类型的定义:
    • 2.2:联合类型的特点:
    • 2.3:联合大小的计算:
    • 2.4:判断当前机器的大小端:

前言:
 之前我们已经学过了自定义类型中的 结构体,忘了的伙计可以再去看看。今天我们继续学习自定义类型中的另外两个成员—— 枚举联合

一:枚举

 枚举顾名思义就是 一 一 列举。把可能的取值 一 一 列举出来,比如我们现实生活中的:一周的星期一到星期日是有限的7天,可以 一 一列举;性别有:男、女、保密,也可以 一 一 列举;月份有12个月也可以 一 一 列举。向这些可以 一 一 列举的数据,我们就可以把他们定义成枚举类型

1.1:枚举类型的定义:

enum Sex//括号里面添加的是枚举未来的可能取值,这些取值是不能被修改的,因此我们把这些值叫做枚举常量
{
	MALE,
	FEMALE,
	SECRET
};
//这就是声明了一个枚举类型

int main()
{
	enum Sex s;//定义一个枚举变量
	return 0;
}

 上面代码中的 enum Sex 就是我们定义出来的一个枚举类型。我们发现它和结构体的声明十分相似,但也有不同的地方,比如:结构体中的关键字是 struct 而枚举的关键字是 enum ;结构体的 { } 里面是结构体的成员列表,而枚举的 { } 里是枚举未来的可能取值,这些值是不能被修改的,因此我们也把这些值叫做枚举常量;最后一点不同在于,结构体的每一个成员后边都要加 : 隔开,而枚举常量之间是用 , 加以区分。

枚举常量的取值:

在这里插入图片描述
 通过打印我们发现,枚举常量的默认取值是从 0 0 0 开始的,每次递增 1 1 1 。当然我们在定义枚举类型的时候,也可以给他们赋初值
在这里插入图片描述
 此时这三个枚举常量的值就不再是 0 0 0 1 1 1 2 2 2 了,而是我们初始化赋值的 1 1 1 2 2 2 4 4 4 。如果只初始化枚举常量其中的某一个,后面的枚举常量会在当前初始化值的基础上,每次自增 1 1 1

在这里插入图片描述
 如上,我们只初始化了枚举常量中的 FEMALE 给它赋值成 2 2 2MALE 还是默认的从 0 0 0 开始,SECRET 则是在它前一个枚举常量 FEMALI 2 2 2 的基础上自增了 1 1 1

注意:
 枚举类型的变量在赋值的时候,最好用枚举常量来赋值

enum Sex//括号里面添加的是枚举未来的可能取值,这些取值是不能被修改的,因此我们把这些值叫做枚举常量
{
	MALE ,
	FEMALE = 2,
	SECRET 
};
//这就是声明了一个枚举类型

int main()
{
	enum Sex s = FEMALE;//最好是这样写
	enum Sex s = 2;//避免这样写 在C++中就会报错
	return 0;
}

1.1:枚举的优点:

  • 增加代码的可读性和可维护性
  • #define 定义的标识符比较,枚举有类型检查,更加严谨
  • 防止了命名污染(封装)
  • 便于调试,#define在调试的时候会完成替换
  • 使用方便,一次可以定义多个变量

1.2:枚举的使用:

enum Color//颜色
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;//避免这样写

一个枚举类型变量的大小是?
 已给枚举变量,只会用来存放一个枚举常量的值,所以一个枚举变量的大小应该就是一个 int 的大小,也就是4个字节。下面我们通过代码来测试一下。
在这里插入图片描述
 可以看出一个枚举类型的大小确实就是4个字节。

二:联合(共用体)

2.1:联合类型的定义:

 联合也是一种特殊的自定义类型,它的关键字是 union 这种类型定义的变量也包含一系列的成员,特征是这些成员公用一块空间(所以联合也叫共用体

union UN
{
	char c;
	int i;
};
//定义了一个共用体类型

int main()
{
	union UN un;//定义了一个共用体变量
	return 0;
}

2.2:联合类型的特点:

 联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员),受限于联合体的特点,我们不会同时使用联合里面的成员,只会用一种的一个。

union UN
{
	char c;
	int i;
};
//定义了一个共用体类型

int main()
{
	union UN un;//定义了一个共用体变量
	printf("%d\n", sizeof(un));
	printf("%p\n", &un);
	printf("%p\n", &un.c);
	printf("%p\n", &un.i);
	return 0;
}
//结果:
4
00EFFA2C
00EFFA2C
00EFFA2C

 可以看出,unun.cun.i它们三个的起始地址都一样,这也说明,联合体的成员确实会共用同一块内存空间。

2.3:联合大小的计算:

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

举个例子:
 大家猜猜下面这个联合体的大小是多少?

union Un1
{
	char c[5];
	int i;
};

int main()
{
	printf("%d\n", sizeof(union Un1));
	return 0;
}

 这里我们可能会想,c 的大小是5个字节,i 的大小是1个字节,取较大的,所以算出这个联合体的大小是5个字节。但实际打印出来的确是 8 8 8 ,说明这个来联合体的大小是 8 8 8 个字节,为什么呢?这是因为,我们在计算的时候忽略了上面联合体大小计算的第二点 —— 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。我们来分析一下这个联合体的大小,首先对数组 c 来说,它的对齐数是从数组一个成员的大小和默认对齐数中取较小的,这里 c 数组是 char 型,所以它的一个成员的大小是 1 1 1 个字节,vs中默认对齐数是 8 8 8 ,故数组 c 的对齐数应该是 1 1 1i 的对齐数是从它自身大小和默认对齐数中取最小的,也就是 4 4 4 ,综上,联合的最大成员,也就是 c 的大小是 5 5 5 个字节,联合中的最大对齐数是 4 4 4 ,显然 5 5 5 不是 4 4 4 的倍数,因此来联合的大小就要对齐到最大对齐数的整数倍, 5 5 5 接下来,只有 8 8 8 是最大对齐数 4 4 4 的倍数,因此最终这个联合体的大小是 8 8 8 个字节。

2.4:判断当前机器的大小端:

方法一:

int main()
{
	int a = 1;// 00 00 00 01
	//假设左边低地址————————>右边高地址
	//小端存储 - - 01 00 00 00
	//大端存储 - - 00 00 00 01
	//因此我们可以通过判断首地址处的一个字节里面存放的是0还是1来判断大小端
	if (*(char*)&a == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

方法二:

union Un
{
	char c;
	int i;
};

int main()
{
	union Un un;
	un.i = 1;
	if (un.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

 方法二这里就是利用了联合体的特性,先把联合体里的 int 型变量赋值成 1 1 1 ,再用联合体里的 char 型变量取访问,因为联合体的成员共用一块空间,且 char 型变量,一次只能访问一个字节,我们就可以通过看 char 类型访问到的是不是 1 1 1 来判断大小端,就不用再像方法一那样,取 int 型的地址,然后再强制转换成 char* 的指针,再去解引用。方法二就显得比较巧妙。

总结:
 今天的分享到这里就结束了,今天我们学习了枚举和联合体这两个自定义类型,知道了如何定义一个枚举变量以及它相较于 #define 的优点。在联合体这一块,我们知道了它的最大特点,即联合体的成员会共用同一块空间,了解了一个联合体大小的计算方法。
 如果觉得对你有帮助的话,记得点赞、评论、收藏


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cin、cin.getline(arr, size)、getline(cin, str)

一、cin使用空白(空格、制表符、换行符)来确定字符串的截止位置 注意下方这段代码 使用cin来接收姓名和甜点名,当我的名字长度大于一个单词长度时,cin直接按空格进行接收,将我输入的xiao接收到name中,wei接…

swiftUI coreml deeplabv3去除背景

现在手机的性能越来越好,好多深度学习的框架都能能够跑在手机上。因此就集成一下一个官方的深度学习model试一下。 其他的框架生成的模型都能通过相应的工具转换成mlmodel用,转换也比较简单。 下面以替换图像去背景为例,不过官方模型这个效果…

概论_第3章_二维随机变量__边缘概率密度

边缘概率密度是二维随机变量中的重点内容, 经常作为一个重要的考点, 必须掌握。一 定义对二维随机变量(X, Y) ,分量X, 或者Y的概率密度称为 (X, Y)的边缘概率密度,简称边缘密度,记为 或者 。边缘密度 或者 可由 二维随机变量的密…

什么是pod(容器组)

pod(容器组) 术语中英文对照: 英文全称英文缩写中文翻译PodPod容器组ContainerContainer容器ControllerController控制器 什么是 Pod 容器组? Pod(容器组)是 Kubernetes 中最小的可部署单元。一个 Pod&a…

基于FPGA的UDP 通信(六)

引言 前文链接: 基于FPGA的UDP 通信(一) 基于FPGA的UDP 通信(二) 基于FPGA的UDP 通信(三) 基于FPGA的UDP 通信(四) 基于FPGA的UDP 通信(五)…

【Spring6源码・AOP】AOP源码解析

上一篇《【Spring6源码・AOP】代理对象的创建》,我们知道了代理是如何创建的,那么它又是如何工作的呢? 创建完代理对象之后,最终,会真正的执行我们的目标方法,但是步入该方法,会进入cglib代理类…

ET框架关于opCode的理解

因为所有的网络消息在发送时候格式都是这样 对于用Protobuf定义的每一消息类型class,都需要定义一个对应消息头code在发送的时候,先将消息体进行序列化,再将code进行序列化,进行组装发送 //这个代码没有进行过优化,会产…

大衣哥给儿媳买回来烟花,是准备加入河南炮击山东大战吗

自从取得抗疫阶段性胜利后,国人就再也难以按捺激动的心情,都想通过放烟花以示庆祝。河南山东属于搭界的两个省,最近就因为放烟花,闹出来不小的笑话,有人甚至戏称炮击事件。 事情的起因是这样的,河南因为地处…

maven的build节点配置

虽然一直在使用maven,但是对于maven的配置还没有深入的了解过。本文以build节点为切入点,主要解释相关maven打包使用到的一些基础配置。 文章目录build节点常用插件spring-boot-maven-pluginmaven-jar-pluginmaven-dependency-plugin注意事项build节点 …

基于javaweb的会议管理系统源码+数据库,javaEE会议管理系统源码

guihaiyidao_git 介绍 javaEE工程 普通的javaEE工程,用idea打开工程即可运行 服务器用的是Tomcat 8.5.722 数据库用的Oracle xe版 数据库可视化工具使用的是PLSQL 相关软件 需要可从百度网盘中获取 链接:https://pan.baidu.com/s/1ZrmfsvQEA4dIP0GF_p…

CSS 布局 - 水平 垂直对齐

CSS 布局 - 水平 & 垂直对齐 那么怎样设置居中对齐呢? 我们可以用margin: auto来设置水平居中对其元素。auto可以防止 元素的宽高溢出,而且也可以平均分配两边的空白。 举例说明: .center {padding: 23px;border: 5px solid red;width: 41%;margin: auto; }那…

【数据结构】单向链表的原理及实现

1.什么是单链表 链表里的数据是以节点的方式表示的,每一个结点的组成是由:元素指针来组成的,元素就是存储数据里的存储单元,指针就是用来连接每一个结点的地址数据。这个以结点的序列来表示线性表被称作为单链表。 单链表是一种…

牛客寒假算法集训营1 补题

标题迷惑大赏 A、World Final? World Cup! 题目描述 众所周知,2022年是四年一度的世界杯年,那么当然要整点足球题。本题需要你模拟一次点球大战。 假设对战双方为A和B,则点球大战中双方会按照ABABABABAB方式来罚点球,即两队交…

【闪电侠学netty】第7章 数据载体ByteBuf的介绍

1. 内容概要 1.1 总结 1.1.1 内存管理 Netty 使用的是堆外内存,需要手动释放,使用引用计数的方式管理内存,当引用计数 0,回收ByteBuf 底层内存 原则:谁使用retain() , 谁释放release() 1.1.2 创建ByteBuf的方式 B…

ASCII码,字符,字符串三者之间的关系

程序调试中遇到问题:在使用sprintf 函数,在转换字符串时,如果遇到0时,会自动认为是结束标志,0以后的内容不会被添加进来。复习一下字符串:一. ASCII码是什么?ASCII 全称为 ( American Standard …

【2023更新】通过硬件触发信号实现OAK多相机之间的同步拍摄

编辑:OAK中国 首发:oakchina.cn 喜欢的话,请多多👍⭐️✍ 内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。 ▌前言 Hello,大家好,这里是OAK中国,我是助手…

经典文献阅读之--NeRF-SLAM(单目稠密重建)

0. 简介 最近几年随着深度学习的发展,现在通过深度学习去预估出景深的做法已经日渐成熟,所以随之而来的是本文的出现《Real-Time Dense Monocular SLAM with Neural Radiance Fields》。这篇文章是一个结合单目稠密SLAM和层次化体素神经辐射场的3D场景重…

【自学Docker 】Docker管理命令大全(下)

文章目录Docker kill命令Docker kill命令概述Docker kill命令语法Docker kill命令参数案例使用容器 ID 杀掉容器使用容器名杀掉容器Docker kill命令总结Docker rm命令Docker rm命令概述Docker rm命令语法Docker rm命令参数案例删除已停止的容器删除正在运行的容器Docker rm命令…

13.拷贝控制

文章目录拷贝控制13.1拷贝、赋值与销毁13.1.1拷贝构造函数合成拷贝构造函数拷贝初始化参数和返回值编译器可以绕过拷贝构造函数13.1.2拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符13.1.3析构函数析构函数完成什么工作什么时候会调用析构函数合成析构函数13.1.4三/五法则需要…

寒假题练——day(4)

题目 1 一个数组中只有两个数字是出现一次&#xff0c;其他所有数字都出现了两次。 编写一个函数找出这两个只出现一次的数字。 #include<stdio.h> int main() {int arr[] { 1, 3, 8, 1, 3, 8, 4, 6 };int num 0;int sz sizeof(arr) / sizeof(arr[0]);int i 0;int…