从概念到实践:揭开枚举与联合体在数字化创新时代的神秘面纱

欢迎来到白刘的领域   Miracle_86.-CSDN博客

系列专栏  C语言知识

先赞后看,已成习惯

   创作不易,多多支持!

在编程的世界中,枚举和联合体是两种非常基础且重要的数据结构。它们各自具有独特的特点和用途,为程序员提供了灵活且强大的工具来构建复杂而高效的程序。

目录

一、联合体

1.1 联合体类型的声明

1.2 联合体的特点

1.3 相同成员的结构体和联合体的比较

1.4 联合体大小的计算

1.5 填坑

二、枚举

2.1 枚举的声明

2.2 枚举的优点

2.3 枚举的使用


一、联合体

1.1 联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。

但是与结构体不同的是,编译器只为联合体中最大的成员分配足够的内存空间。联合体的一个显著特点是它的所有成员共同使用同一块内存空间。因此,联合体也被称为“共用体”。

由于所有成员共享同一块内存,所以当给联合体的其中一个成员赋值时,其他成员的值也会跟着发生变化,因为它们实际上是在操作同一块内存的不同部分。这种特性使得联合体在某些特定的编程场景中非常有用,但也需要在使用时格外小心,以避免出现意料之外的数据覆盖或混淆。

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

运行结果:

为什么会得到这样的结果呢?这就不得不提一下联合体的特点了。

1.2 联合体的特点

联合的成员是共同使用同一块内存空间的,因此一个联合变量的大小至少是最大成员的大小。这是因为联合至少需要有能力保存最大的那个成员,以确保无论使用哪个成员,都能有足够的空间来存储它的值。

//代码1#include <stdio.h>
//联合类型的声明
union Un
{char c;int i;
};
int main()
{//联合变量的定义union Un un = { 0 };// 下⾯输出的结果是⼀样的吗?printf("%p\n", &(un.i));printf("%p\n", &(un.c));printf("%p\n", &un);return 0;
}

运行结果:

//代码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;
}

运行结果:

从上述结果我们可以看出,代码1的三个地址相同,说明成员共用一个地址;代码2将i的第四个字节的内容修改为55了,那我们就可以画出un的内存图:

1.3 相同成员的结构体和联合体的比较

union un
{char c;int i;
};struct s
{char c;int i;
};

 

结构体中的每个成员都有自己独立的内存空间,各个成员互不干涉,同时存在,遵循内存对齐原则。因此,一个结构体变量的总长度等于所有成员的长度之和。相反,联合体的成员共享同一块内存空间,同一时间只有一个成员可以使用这块内存。这意味着联合体比结构体在内存使用上更为节约。上篇文章我们介绍了结构体大小的计算,我们学会了对齐规则:

穿越代码之海:探寻结构体深层逻辑,展望未来应用新天地-CSDN博客

那联合体的大小怎么计算呢?

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

Un1,最大成员为char[5],占五个字节,最大对齐数为4,5不是4的整数倍,所以补3个字节,所以大小为8。

Un2,最大成员为short[2],占14个字节,最大对齐数为4,补到16,故大小为16。

来看运行结果:

使用联合体确实可以节省空间。例如,假设我们要搞一个活动,并上线一个礼品兑换单。在这个礼品兑换单中,有三种商品:图书、杯子和衬衫。每种商品都有一些共同的属性,如库存量和价格,但也有一些与商品类型相关的特定信息。

图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜色、可选尺寸

如果我们为每种商品单独定义一个结构体,那么每个结构体都会占用其所有成员所需的内存空间,即使某些成员在某一时刻并不被使用。这样会造成内存的浪费。

struct gift_list
{//公共属性int stock_number;//库存量double price; //定价int item_type;//商品类型//特殊属性char title[20];//书名char author[20];//作者int num_pages;//⻚数char design[30];//设计int colors;//颜⾊int sizes;//尺⼨
};

上述的结构确实设计得相对简单,使用起来也很方便。然而,这种设计方式包含了所有礼品的各种属性,这会导致结构体的大小偏大,从而比较浪费内存。因为在礼品兑换单中的商品,只有部分属性信息是常用的。

比如,如果商品是图书,那么就不需要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];//设计}mug;struct{char design[30];//设计int colors;//颜⾊int sizes;//尺⼨}shirt;}item;
};

我们可以定义一个包含基础信息的结构体(如库存量和价格),然后在这个结构体中包含一个联合体,该联合体可以存储图书、杯子和衬衫的特定信息。这样,我们就可以在一个结构体实例中存储任意一种商品的信息,而无需为每种商品都分配完整的内存空间。

通过这种方式,使用联合体可以有效地节省空间,并提高内存的利用率。

1.5 填坑

在前面的大小端中,我们挖了个坑还记得吗?

解码新时代内存架构:探秘数据在内存中的灵动驻足-CSDN博客

这段代码用来判断机器是大端还是小端。

我们用到了union的特点,成员共用一个内存空间。也就意味着我改变i的话,c也会跟着改变一个字节。我将i设置为1,如果c是0,说明是小端,反之为大端。

二、枚举

2.1 枚举的声明

枚举顾名思义就是一一列举,即把可能的取值一一列举出来。

在现实生活中,我们经常会遇到需要枚举的情况。

比如一周的星期一到星期日,是有限的7天,我们可以一一列举出来。

同样,性别有男、女、保密等选项,也可以一一列举。

月份有12个,也可以进行一一列举。

此外,像化学中的三原色,也是可以一一列举的。

enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
enum Sex//性别
{MALE,FEMALE,SECRET
};
enum Color//颜⾊
{RED,GREEN,BLUE
};

以上定义的 enum Dayenum Sexenum Color 都是枚举类型。

{} 中的内容是枚举类型的可能取值,也被称为枚举常量。

这些可能取值都是有值的,默认从0开始,依次递增1。当然在声明枚举类型的时候可以赋初值。

enum Color//颜⾊
{RED = 2,GREEN = 4,BLUE = 8
};

2.2 枚举的优点

为什么使用枚举(Enumeration)?
我们可以使用#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.rhkb.cn/news/302155.html

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

相关文章

(一)基于IDEA的JAVA基础12

一维数组 为什么使用数组: 当我们需要存储一系列数据的时候&#xff0c;就需要用到数组&#xff0c;如果不使用数组&#xff0c;我们就要需要一个一个的去声明变量&#xff0c;这样浪费内存空间&#xff0c;同时效率低下。 什么是数组: 数组本身就是一个变量&#xff0c;只…

Redis从入门到精通(六)Redis实战(三)优惠券秒杀

↑↑↑下载测试项目原代码↑↑↑ 文章目录 前言4.3 优惠券秒杀4.3.1 数据表与实体类4.3.2 添加优惠券4.3.2.1 添加普通券代码4.3.2.2 添加秒杀券代码 4.3.3 实现秒杀下单4.3.3.1 秒杀下单逻辑分析4.3.3.2 获取秒杀订单ID4.3.3.3 获取用户ID4.3.3.4 实现秒杀下单 前言 Redis实战…

diffusion model(十五) : IP-Adapter技术小结

infopaperhttps://arxiv.org/pdf/2308.06721.pdfcodehttps://github.com/tencent-ailab/IP-Adapterorg.Tencent AI Lab个人博客地址http://myhz0606.com/article/ip_adapter 1 Motivation 为了对文生图diffusion model进行特定概念的定制&#xff0c;常用LoRA[1]、textual in…

JDK下载及安装说明

1&#xff0e;JDK下载 访问oracle官网&#xff1a;http://www.oracle.com 在首页点击Downloads&#xff0c;进入oracle软件下载页。 在下载页面&#xff0c;点击Java。 选择Java (JDK) for Developers&#xff0c;点击。 在 Java SE Downloads 页面&#xff0c;点击中间的DO…

装机指导。

everything winrar snipaste cmake git tortoisegit tortoisesvn inno setup vs2022 安装的时候注意sdk路径一定要默认&#xff01;&#xff01; 否则你会发现在你的sdk安装路径的根盘符下会多出一个Windows Kits&#xff0c;强迫症接受不了 默认的会跟已有的装在一起…

【Python系列】读取 Excel 第一列数据并赋值到指定列

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Linux的学习之路:4、权限

一、Linux权限的概念 权限我们都熟悉&#xff0c;最常见的就是在看电视时需要vip这个就是权限&#xff0c;然后在Linux就是有两个权限&#xff0c;就是管理员也就是超级用户和普通的用户 命令&#xff1a;su [用户名] 功能&#xff1a;切换用户。 例如&#xff0c;要从root用户…

ZLMediaKit ubantu 下编译

1、获取代码 #国内用户推荐从同步镜像网站gitee下载 git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit cd ZLMediaKit #千万不要忘记执行这句命令 git submodule update --init二、依赖库 Debian系(包括ubuntu&#xff09;系统下安装依赖的方法&#xff1a; #除了…

Python-VBA函数之旅-ascii函数

ascii函数在Python中主要用于将对象(特别是字符和字符串)转换为它们的ASCII表示形式。这种转换在处理文本数据、调试代码以及确保文本以 ASCII 格式存储或传输时非常有用。常见应用场景有&#xff1a; 1、调试和文本处理&#xff1a;当处理包含非ASCII字符(如Unicode字符)的文…

景联文科技:为AI大模型提供高质海量训练数据

在全球AI浪潮的推动下&#xff0c;大量训练数据已成为AI算法模型发展和演进中的关键一环。 艾瑞咨询数据显示&#xff0c;包括数据采集、数据处理&#xff08;标注&#xff09;、数据存储、数据挖掘等模块在内的AI基础数据服务市场&#xff0c;将在未来数年内持续增长。 预计到…

算法:完全背包问题dp

文章目录 一、完全背包问题的特征二、定义状态三、状态转移四、降维优化五、参考例题5.1、Acwing&#xff1a;3.完全背包问题5.2、Acwing&#xff1a;900. 整数划分 一、完全背包问题的特征 完全背包问题是动态规划中的一种经典问题&#xff0c;它的主要特征可以总结如下&…

ES6中 Promise的详细讲解

文章目录 一、介绍状态特点流程 二、用法实例方法then()catchfinally() 构造函数方法all()race()allSettled()resolve()reject() 三、使用场景# 参考文献 一、介绍 Promise&#xff0c;译为承诺&#xff0c;是异步编程的一种解决方案&#xff0c;比传统的解决方案&#xff08;…

2024/4/5—力扣—在排序数组中查找元素的第一个和最后一个位置

代码实现&#xff1a; 思路&#xff1a;二分法 方法一&#xff1a;分别查找左右侧边界 /*** Note: The returned array must be malloced, assume caller calls free().*/ int GetTargetFirstPosition(int *nums, int numsSize, int target) {int l 0, r numsSize - 1;while …

springboot无人便利店信息管理系统ssm+tomcat+java

jdk版本&#xff1a;1.8 及以上 ide工具&#xff1a;IDEA 或者eclipse 数据库: mysql 编程语言: java 框架&#xff1a;SSM/springboot都有 maven: 3.6.1 前端&#xff1a;layuibootstrapjsp 详细技术&#xff1a;HTMLCSSJSjspspringmvcmybatisMYSQLMAVENtomcat本文以java实现…

Jenkins使用-绑定域控与用户授权

一、Jenkins安装完成后&#xff0c;企业中使用&#xff0c;首先需要绑定域控以方便管理。 操作方法&#xff1a; 1、备份配置文件&#xff0c;防止域控绑定错误或授权策略选择不对&#xff0c;造成没办法登录&#xff0c;或登录后没有权限操作。 [roottest jenkins]# mkdir ba…

iOS 开发中上传 IPA 文件的方法(无需 Mac 电脑

引言 在 iOS 开发中&#xff0c;将 IPA 文件上传到苹果开发者中心是一个重要的步骤。通常情况下&#xff0c;我们需要使用 Mac 电脑上的 Xcode 或 Application Loader 工具来完成这个任务。然而&#xff0c;如果你没有 Mac 电脑&#xff0c;也没有关系&#xff0c;本文将介绍一…

Windows编译运行yolov9-bytetrack-tensorrt (C++)

Windows编译运行yolov9-bytetrack-tensorrt&#xff08;C&#xff09; 1 基础环境2 编译yolov9-bytetrack-tensorrt&#xff08;1&#xff09;下载yolov9-bytetrack-tensorrt源码&#xff08;2&#xff09;修改CMakeLists.txt&#xff08;3&#xff09;CMake编译 3 yolov9模型转…

css实现各级标题自动编号

本文在博客同步发布&#xff0c;您也可以在这里看到最新的文章 Markdown编辑器大多不会提供分级标题的自动编号功能&#xff0c;但我们可以通过简单的css样式设置实现。 本文介绍了使用css实现各级标题自动编号的方法&#xff0c;本方法同样适用于typora编辑器和wordpress主题…

有没有适合运动佩戴的耳机?最适合运动使用的开放式耳机推荐

哪种耳机更适合运动&#xff0c;挂耳式和入耳式哪种更合适呢&#xff1f;答案是挂耳式的耳机更适合运动&#xff0c;适用的场景也更多。无论你是在家还是在外面运动&#xff0c;都很合适。挂耳式耳机也可以叫开放式耳机&#xff0c;它开放式的设计可以让我们更好的感知到周围嘈…

1132A安捷伦1132A示波器探头

181/2461/8938产品概述&#xff1a; 带宽: 输入阻抗: 差分输入R: 50千欧差分输入C: 0.27-0.34 pF单端输入电阻:25千欧单端输入C: 0.44-0.67 pF 连通性: E2669A差分/单端连接套件E2668A单端连接套件用于InfiniiMax探头的E2675A差分浏览器套件E2677A InfiniiMax 12 GHz差分焊…