首页 > 其他分享 >自定义类型:联合和枚举

自定义类型:联合和枚举

时间:2024-09-18 16:19:30浏览次数:3  
标签:自定义 代码 联合体 枚举 内存 类型 成员

目录

引言

一.联合体

1.1 联合体的定义

1.2 联合体的声明 

1.3 联合体的特点

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

1.5 联合体大小的计算

1.6 联合体的作用

1.7 联合体的小练习

二.枚举类型 

2.1 枚举的定义

2.2 枚举的声明

2.3 枚举的作用

2.4 枚举的使用示例

 后记


引言

之前我们学习了一种自定义类型:结构体,今天我们来学习另一种自定义类型:联合以及枚举。

我们先来学习联合体,那么什么是联合体呢?下面我们来具体学习。

一.联合体

1.1 联合体的定义

在C语言中,联合体(Union)是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型但在任何给定时间只能存储其中一个成员的值。这意味着联合体中的所有成员共享同一块内存空间,并且联合体的大小至少足够大,能够存储其最大成员。

1.2 联合体的声明 

联合体的声明类似于结构体的声明,但使用union关键字。在声明时,你需要指定联合体的名称以及它包含的各个成员的类型和名称。

 

 这里,Un是一个联合体的名称,它包含了两个成员:一个int类型的a,一个char类型的c。

1.3 联合体的特点

联合的成员是共用同⼀块内存空间的,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

下面我们通过分析两段代码来学习联合体的特点:

这段代码的结果是什么呢?

 

在这里我们发现:代码1输出的三个地址⼀模⼀样 

下面我们来看代码2

这段代码的结果是什么呢?

代码2的输出,我们发现将i的第4个字节的内容修改为55了。 我们仔细分析就可以画出,un的内存布局图。

那么为什么上述两段代码会出现这样的结果呢?这就要说到联合体的特点了

联合体有如下特点: 

内存共享联合体的所有成员共享同一块内存空间。这意味着,当你给联合体的一个成员赋值时,其他成员的值会被覆盖,因为它们实际上指向的是同一块内存。

大小联合体的大小至少足够大,能够存储其最大成员。但是,具体大小还可能受到编译器填充(padding)和对齐(alignment)要求的影响。

匿名联合体:C11标准引入了匿名联合体的概念,允许直接访问联合体的成员,而不需要通过联合体变量名。

用途联合体常用于需要存储不同类型数据,但每次只使用其中一种类型的情况。例如,在处理网络通信协议时,不同的数据包可能具有不同的格式,但可以使用同一个联合体来接收这些数据,并根据需要解释它们。

学习了上述联合体的特点,我们再来看这两段代码就容易理解了。

代码1中,由于联合体的所有成员共享同一块内存空间,所以代码1输出的三个地址⼀模⼀样。

代码2中,由上述的图可知,当你给联合体的一个成员赋值时,其他成员的值会被覆盖,因为它们实际上指向的是同一块内存,则有了i的第4个字节的内容修改为55,从而改变了输出。

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

我们再对比一下相同成员的结构体和联合体的内存布局情况。

结构体:

它的内存示意图如下:

  

联合体: 

它的内存示意图如下:

1.5 联合体大小的计算

• 联合的大小至少是最大成员的大小。

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

 下面我们来看一段代码:

 

 

那么为什么会出现这样的结果呢?

下面我们通过图像来分析:

 

注意:最大成员的判断是按照数据类型来判断的,char c[5]虽然是字符数组,占据5个字节,但它的类型依旧是char,比int小,则最大成员大小为4,最大对齐数是4,故占据内存数为它的整数倍8

Un2也是同理:short c[7]占据14个字节,但short所占字节为2,比int的所占字节4要小,所以最大成员大小为4 故占据内存数为它的整数倍16

1.6 联合体的作用

使用联合体是可以节省空间的

举例:

比如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:

图书、杯子、衬衫。

每⼀种商品都有:

库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、页数

杯子:设计

衬衫:设计、可选颜色、可选尺寸。

面对这种问题,可能小伙伴们就会直接用结构体来书写,我们也写出它的结构体形式:

 

上述的结构其实设计的很简单,用起来也方便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常用的。比如: 商品是图书,就不需要design、colors、sizes。 所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以减少所需的内存空间,⼀定程度上节省了内存。 

1.7 联合体的小练习

学习了联合体,下面我们来用联合体实现一个程序:判断当前机器是大端字节序还是小端字节序

二.枚举类型 

枚举(Enumeration)是一种用户定义的类型,它允许程序员为整数常量指定名称,从而增加代码的可读性和可维护性。

2.1 枚举的定义

枚举类型的定义通常包含在一个enum关键字后紧跟的标识符(即枚举类型的名称)中,然后是花括号{}内的一组命名的整型常量(称为枚举成员或枚举器)。枚举成员之间通常用逗号分隔。

 

2.2 枚举的声明

枚举类型的声明是指创建该类型变量的过程。一旦枚举类型被定义,就可以像使用其他基本数据类型(如intfloat等)一样声明该类型的变量。 

 

2.3 枚举的作用

1.增加代码的可读性和可维护性
2.和#define定义的标识符比较枚举有检查类型,更加严谨
3.防止了命名污染(封装)
4.便于调试
5.使用方便,一次可以定义多个常量

2.4 枚举的使用示例

 

那是否可以拿整数给枚举变量赋值呢?在C语言中是可以的,但是在C++是不行的,C++的类型检查比较严格。 

 后记

一个中秋又摆烂了,得振作起来好好学哦

喜欢这篇文章的小伙伴点点赞,点点关注哦,谢谢各位大佬们的支持!!!

共勉!!! 

 

标签:自定义,代码,联合体,枚举,内存,类型,成员
From: https://blog.csdn.net/2401_85548793/article/details/142251856

相关文章

  • Rust有指针类型数据吗?是否可以查看一个变量的内存地址?
    在Rust中,虽然不像C/C++那样直接使用传统的指针类型,但Rust依然有指针的概念,且提供了多种安全的方式来操作和管理内存。你可以通过一些Rust的特性查看变量的内存地址并安全地进行指针操作。1.引用(References)Rust的引用(&和&mut)可以理解为一种安全的、受所有权规则和借......
  • 从零开始学SQL注入(sql十大注入类型):技术解析与实战演练
    环境工具:burpsuite靶场:sqli服务器:centos7数据库:mysql5.7什么是Sql注入?SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。由于以下的环境都是MySQL数据库,所以先了解点......
  • [Clickhouse] Clickhouse 函数 : 数据类型转换
    0引言如无特殊说明,ck版本为21.3.4.251数据类型的支持情况查看当前受支持的数据类型select*fromsystem.data_type_families--selectname,case_insensitive,alias_tofromsystem.data_type_families;outputname|case_insensitive......
  • java_day2_常量,变量,数据类型,运算符
    一、常量常量:在Java程序运行过程中其值不能发生改变的量分类:1、字面值常量:整数常量表示所有的整数,包括负数10-8小数常量表示所有的小数1.23-3.14布尔常量truefalse空常量null......
  • Shader Graph自定义渐变色节点Gradiant
    ShaderGraph自定义渐变色节点GradiantUnity自带Shader中的Gradiant不能暴露在外部使用定义CustomFunction来制作暴露给外部的GradiantShaderGraph节点图CustomFunction代码if(inputValue<location1){outFloat=color1;}else......
  • 自定义浏览器滚动条样式
    自定义浏览器滚动条样式Webkit内核的浏览器,可以通过-webkit-scrollbar等属性进行重置/*设置尺寸*/::-webkit-scrollbar{width:10px;height:10px;}/*滚动条两端的按钮*/::-webkit-scrollbar-button{background-color:red;width:100px;height:10px;}......
  • PyQt / PySide + Pywin32 + ctypes 自定义标题栏窗口 + 完全还原 Windows 原生窗口边
    项目地址:GitHub-github201014/PyQt-NativeWindow:AclassofwindowincludenativeEvent,usePySideorPyQtandPywin32andctypesAclassofwindowincludenativeEvent,usePySideorPyQtandPywin32andctypes-github201014/PyQt-NativeWindowhttps://githu......
  • 螺丝、螺母、垫片等紧固件常用类型详细介绍
    螺钉、螺母、垫片等紧固件介绍螺钉杯头内六角首先介绍一下杯头内六角,杯头内六角是我们用的最常见的一种螺钉,如果你对选择螺钉没有什么想法,可以直接无脑选杯头内六角去使用。比如说我们有一个零件加工了通孔,另一个零件加工了螺纹孔,我们只要把螺钉穿过通孔的零件,然后锁......
  • VUE框架CLI组件化组件绑定自定义事件时回调函数的this对象------VUE框架
    <template> <div> <!--内置函数的实现步骤--> <!--提供事件源,给事件源绑定事件,编写回调函数,将回调函数和事件进行绑定--> <!--等待事件的触发,事件触发执行回调函数--> <!--组件的自定义事件实现步骤--> <button@click="Hello()">你好</button> <!--给Us......
  • Vue自定义指令以及项目中封装过的自定义指令
     自定义指令Vue 自定义指令是Vue.js框架中一个非常强大的功能,它允许你注册一些全局或局部的自定义DOM操作指令,以便在模板中复用。自定义指令通过Vue.directive()方法进行全局注册,或者在组件的directives选项中局部注册。自定义指令的钩子函数Vue自定义指令可以包含几个......