C 语言联合与枚举:自定义类型的核心解析

news2025/4/21 21:04:51

目录

1.联合体

1.1联合体的声明与创建

 1.2联合体在内存中的存储

 1.3相同成员的结构体与内存比较

1.4联合体内存空间大小的计算

1.5联合体的应用

 2.枚举类型

2.1枚举变量的声明

2.2枚举变量的优点

2.3枚举的使用 


上篇博客中,我们通过学习了解了C语言中一种自定义类型结构体的相关知识,那么该语言中是否还拥有相似的自定义类型呢?这将是我们今天学习的目标。


1.联合体

联合体其实跟结构体类似,也是由一个或多个成员构成,这些成员可以是不同类型。

以下是联合体的定义:

在C语言中,联合体(Union)是一种特殊的数据结构,允许在同一内存位置存储不同的数据类型。


1.1联合体的声明与创建

union un {
	int n;
	char ch;
};

int main()
{
	//声明
	union un u1;

	union un* pu = &u1;

	u1.ch = 'w';
	printf("%c\n", u1.ch);
	printf("%c\n", pu->ch);
	u1.n = 5;
	printf("%d\n", u1.n);
	printf("%d\n", pu->n);
	return 0;
}

我们在上面的代码中可以看到,联合体和结构体有非常多类似的地方,创建,声明,访问成员变量都很相似。


 1.2联合体在内存中的存储

编译器在为联合体分配内存时,并不会像结构体一样为每个成员变量都分配内存,它只会分配在内存中占用最大空间的成员变量的空间,其他变量将会于该变量共用这一块空间,所以联合体又叫共用体。所以有一点要注意:给联合体其中一个变量赋值,其他成员的值往往也会跟着变化。

从第一个代码的结果我们可以发现:联合体本身和联合体的成员变量的首个字节地址时相同的。第二个代码我们分别给变量 ic 赋值,发现 i 的结果会被 c 的赋值给覆盖掉,画出它们的内存布局图:


 1.3相同成员的结构体与内存比较

struct S
{
	char c;
	int i;
};

struct S s = { 0 };


union Un
{
 char c;
 int i;
};
union Un un = { 0 };

 我们画出它们的内存空间图进行比较:

 我们可以看到,结构体的每个成员都有自己的内存空间,而联合体中 ic 共工用一块空间的。

1.4联合体内存空间大小的计算

 在前面我们说过,编译器只会分配联合体在内存中占用最大空间的成员变量的空间,其实这是不全面的,他还有以下两条规则:

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

我们看下面代码:

 第一个联合体un1内部有两个变量,一个是char型数组,一个是 int 类型,计算字符型数组的对齐数时,我们并不会将它的对齐数看作5,而是将其与char类型一样看待,所以他的对齐数是1,而整型类型的对齐数是4,所以un1的对齐数为4,但是该联合体最大成员大小是5,所以该联合体大小为8。

 第一个联合体un2内部也是两个变量,一个是short类型数组,一个是int类型,计算short型数组的对齐数时,也是一样的规则,将其与short类型一样看待,所以他的对齐数是2,而整型类型的对齐数是4,所以un1的对齐数为4,但是该联合体最大成员大小是34,所以该联合体大小为36。

1.5联合体的应用

使用联合体时,因为给它分配的内存空间要少于同样类型结构体,所以使用联合体是要更节省空间的,我们来句一个例子。

我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、⻚数

杯⼦:设计

衬衫:设计、可选颜⾊、可选尺⼨

我们不加思索,直接写出结构体:

struct gift_list
{
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	char title[20];//书名
	char author[20];//作者
	int num_pages;//页数

	char design[30];//设计
	int color;//颜色
	int szie;//尺寸
};

 上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的⼤⼩就会偏⼤,⽐较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。⽐如: 商品是图书,就不需要design、colors、sizes。

所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以介绍所需的内存空间,⼀定程度上节省了内存。

struct gift_list
{
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	union 
	{
		struct 
		{
			char title[20];//书名
			char author[20];//作者
			int num_pages;//页数
		}book;

		struct
		{
			char design[30];//设计
		}cup;

		struct
		{
			char design[30];//设计
			int color;//颜色
			int szie;//尺寸
		}shirt;
	}item;
};

 下面我们再来做一个熟悉的练习,写一个程序,判断当前机器是大端还是小端?为什么说熟悉呢?因为我们在之前的博客里已经讲过这道题了,之前我们时这样做的:

int main()
{
	int n = 1;
	int* ps = &n;
	if (*((char*)ps) == 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}

之前我们是用了强制转换来这道题的,学习了联合体后,我们有没有其他的思路呢?看下面代码:

union
{
	int i;
	char c;
}un;

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

这个代码利用了联合体内变量共用同一块内存,如果是小端存储模式,将i赋值为1,那么c也会被赋值为1,如果没有,则证明是大端存储模式。 

 2.枚举类型

2.1枚举变量的声明

枚举顾名思义就是⼀⼀列举。
把可能的取值⼀⼀列举。
⽐如我们现实⽣活中:
⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
性别有:男、⼥、保密,也可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举
三原⾊,也是可以意义列举
这些数据的表⽰就可以使⽤枚举了。
enum Month
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

enum Sex
{
	male,
	female,
	secret,
};

enum Color
{
	red,
	green,
	blue
};
以上定义的 enum Day enum Sex enum Color 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫 枚举常量 。
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。
//默认
enum Color
{
	red = 0,
	green = 1,
	blue = 2
};

enum Color
{
	red = 1,
	green = 5,
	blue = 9
};

2.2枚举变量的优点

我们可以使⽤ #define 定义常量,为什么⾮要使⽤枚举?
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符⽐较枚举有类型检查,更加严谨。
3. 便于调试,预处理阶段会删除 #define 定义的符号
4. 使⽤⽅便,⼀次可以定义多个常量
5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

2.3枚举的使用 

enum Color//颜⾊
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
那是否可以拿整数给枚举变量赋值呢?在C语⾔中是可以的,但是在C++是不⾏的,C++的类型检查⽐较严格。

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

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

相关文章

基于Canal+Spring Boot+Kafka的MySQL数据变更实时监听实战指南

前期知识背景 binlog 什么是binlog 它记录了所有的DDL和DML(除 了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。一般来说开启二进制日志大概会有1%的性能损耗。 binlog分类 MySQL Bi…

MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境

文章目录 一、服务器选型——给数据库一个舒适的家二、系统调优——打造高性能跑道三、MySQL配置——让数据库火力全开四、监控体系——数据库的体检中心五、备份恢复——数据安全的最后防线六、主从复制——数据同步的艺术七、安全加固——守护数据长城 引言:从小白…

【MySQL】MySQL的基础语法及其语句的介绍

1、基础语法 mysql -h【主机名】 -u【用户名】 -p //登录MySQL exit或quit; //退出MySQL show database; //查看MySQL下的所有数据库 use 【数据库名】; //进入数据库 show tables; //查看数据库下的所有表名 *MySQL的启动和关闭 &am…

【计算机视觉】三维视觉项目 - Colmap二维图像重建三维场景

COLMAP 3D重建 项目概述项目功能项目运行方式1. 环境准备2. 编译 COLMAP3. 数据准备4. 运行 COLMAP 常见问题及解决方法1. **编译问题**2. **运行问题**3. **数据问题** 项目实战建议项目参考文献 项目概述 COLMAP 是一个开源的三维重建软件,专注于 Structure-from…

ALSA架构学习2(驱动MAX98357A)

1 前言和环境 之前其实写过两篇,一篇是讲ALSA,一篇是I2S。 ALSA架构学习1(框架)_alsa框架学习-CSDN博客 总线学习5--I2S_max98357接喇叭教程-CSDN博客 在ALSA那篇的结尾,也提了几个小练习。比如: ### 4…

数据结构*集合框架顺序表-ArrayList

集合框架 常见的集合框架 什么是顺序表 顺序表是一种线性表数据结构,它借助一组连续的存储单元来依次存储线性表中的数据元素。一般情况下采用数组存储。 在数组上完成数据的增删查改。 自定义简易版的顺序表 代码展示: public interface IArray…

VMware Workstation 保姆级 Linux(CentOS) 创建教程(附 iso)

文章目录 一、下载二、创建 一、下载 CentOS-7.9-x86_64-DVD-2009.iso 二、创建 VMware Workstation 保姆级安装教程(附安装包) VMware Workstation 保姆级安装教程(附安装包) VMware Workstation 保姆级安装教程(附安装包)

软考-信息系统项目管理师-2 信息技术发展

总结思维导图 云计算(掌握) (3)多租户和访问控制管理访问控制管理是云计算应用的核心问题之一云计算访问控制的研究主要集中在云计算访问控制模型、基于ABE密码体制的云计算访问控制、云中多租户及虚拟化访问控制研究云中多租户及虚拟化访问控制是云计算的典型特征。 大数据(…

Spring Boot JPA 开发之Not an entity血案

项目状况介绍 项目环境 JDK 21Spring Boot 3.4.3Hibernate: 6.6.13.Final项目描述 因为是微服务架构,项目层级如下 project-parent project-com project-A … project-X 其中: project-parent定义依赖库的版本project-com 定义了一些公用的方法和配置,包括持久层的配置。…

HTMLCSS实现轮播图效果

这段代码实现了一个具有自动轮播、手动切换功能的图片轮播图,并且配有指示器(小圆点)来显示当前图片位置。轮播图可通过左右箭头按钮进行手动切换,也能自动定时切换,当鼠标悬停在轮播图上时,自动轮播会暂停…

嵌入式学习——opencv图像库编程

环境配置 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和图像处理库,广泛用于各种计算机视觉任务,如图像处理、视频分析、人脸识别、物体检测、机器学习等。它提供了丰富的函数和工具,用于处理…

【每日八股】复习 MySQL Day1:事务

文章目录 复习 MySQL Day1:事务MySQL 事务的四大特性?并发事务会出现什么问题?MySQL 事务的隔离级别?不同事务隔离级别下会发生什么问题?MVCC 的实现原理?核心数据结构版本链构建示例可见性判断算法MVCC 可…

外接键盘与笔记本命令键键位不同解决方案(MacOS)

文章目录 修改键位第一步:打开设置第二步:进入键盘快捷键第三步:修改修饰键设置第四步:调整键位第五步:保存设置tips ikbc c87键盘win键盘没反应的解决亲测的方法这是百度的答案标题常规组合键尝试‌:型号差…

kotlin知识体系(五) :Android 协程全解析,从作用域到异常处理的全面指南

1. 什么是协程 协程(Coroutine)是轻量级的线程,支持挂起和恢复,从而避免阻塞线程。 2. 协程的优势 协程通过结构化并发和简洁的语法,显著提升了异步编程的效率与代码质量。 2.1 资源占用低(一个线程可运行多个协程)…

vscode stm32 variable uint32_t is not a type name 问题修复

问题 在使用vscodekeil开发stm32程序时,发现有时候vscode的自动补全功能失效,且problem窗口一直在报错。variable “uint32_t” is not a type name uint32_t 定义位置 uint32_t 实际是在D:/Keil_v5/ARM/ARMCC/include/stdint.h中定义的。将D:/Keil_v5…

Formality:Bug记录

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 本文记录博主在使用Synopsys的形式验证工具Formality中遇到的一个Bug。 Bug复现 情况一 // 例1 module dff (input clk, input d_in, output d_out …

【java+Mysql】学生信息管理系统

学生信息管理系统是一种用于管理学生信息的软件系统,旨在提高学校管理效率和服务质量。本课程设计报告旨在介绍设计和实现学生信息管理系统的过程。报告首先分析了系统的需求,包括学生基本信息管理、成绩管理等功能。接着介绍了系统的设计方案&#xff0…

小白从0学习网站搭建的关键事项和避坑指南(2)

以下是针对小白从零学习网站搭建的 进阶注意事项和避坑指南(第二期),覆盖开发中的高阶技巧、常见陷阱及解决方案,帮助你在实战中提升效率和质量: 一、进阶技术选型避坑 1. 前端框架选择 误区:盲目追求最新…

Windows 10 上安装 Spring Boot CLI详细步骤

在 Windows 10 上安装 Spring Boot CLI 可以通过以下几种方式完成。以下是详细的步骤说明: 1. 手动安装(推荐) 步骤 1:下载 Spring Boot CLI 访问 Spring Boot CLI 官方发布页面。下载最新版本的 .zip 文件(例如 sp…

vue2技术练习-开发了一个宠物相关的前端静态商城网站-宠物商城网站

为了尽快学习掌握相关的前端技术,最近又实用 vue2做了一个宠物行业的前端静态网站商城。还是先给大家看一下相关的网站效果: 所以大家如果想快速的学习或者掌握一门编程语言,最好的方案就是通过学习了基础编程知识后,就开始利用…