【C语言】自定义类型之联合和枚举

目录

  • 1. 前言
  • 2. 联合体
    • 2.1 联合体类型的声明
    • 2.2 联合体的特点
    • 2.3 相同成员的结构体和联合体对比
    • 2.4 联合体大小的计算
    • 2.4 判断当前机器的大小端
  • 3. 枚举
    • 3.1 枚举类型的声明
    • 3.2 枚举类型的优点
    • 3.3 枚举类型的使用

1. 前言

在之前的博客中介绍了自定义类型中的结构体,有想了解的可以点这个链接:link
今天来分享另外两种类型:联合和枚举。

2. 联合体

2.1 联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最大的成员分配足够的内存空间。
联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体

-----------------------------------------------------------------------------------------

我们举个例子来看一下:

在这里插入图片描述
我们发现在联合体中的大小占4个字节,这是为什么呢?

我们来看看它每个成员的地址
在这里插入图片描述
我们发现那三个的地址都是一样的。
改到32位平台上发现内存地址还是一样的。
在这里插入图片描述
也就是说它们共用一块空间
在这里插入图片描述

-----------------------------------------------------------------------------------------

给联合体其中⼀个成员赋值,其他成员的值也跟着变化。
在同一个时间点只能使用一个联合体成员。

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

在这里插入图片描述
我们来看看在内存中的变换:
在这里插入图片描述
在这里插入图片描述
代码的输出,我们发现将i的第4个字节的内容修改为55了。
我们仔细分析就可以画出,un的内存布局图。
在这里插入图片描述

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

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

结构体的代码:

struct S
{
 char c;
 int i;
};
struct S s = {0};

联合体的代码:

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

在这里插入图片描述
对于结构体来说就占了8个字节,浪费了3个字节,而联合体占了4个字节。

2.4 联合体大小的计算

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

举个例子:计算下面两个联合体的大小?

#include <stdio.h>

union Un1
{
    char c[5];//5   1 8 1
    int i;//4       4 8 4
};

union Un2
{
    short c[7];//14   2   8  2
    int i;//4         4   8  4
};

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

在这里插入图片描述
对于Un1,char c[5],占五个字节,char类型占1个字节,对齐数默认是8,对比之后取对齐数取1。 int i,占4个字节,对齐数默认是8,对比之后取对齐数取4。所以等于5时,5不是4的倍数,就得浪费3个字节,取8。

对于Un2 ,short c[7]占14个字节,short占2个,对齐数默认是8,对比之后取对齐数取2; int i,占4个字节,对齐数默认是8,对比之后取对齐数取4。所以等于14时,14不是4的倍数,就得浪费2个字节,取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;//尺⼨
};

上述的结构其实设计的很简单,用起来也方便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常用的。

所以我们就可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。
用联合体来实现,代码如下:

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

这里使用了匿名结构体,这里的书、杯子和衬衫是不能同时存在的。就按照最大的结构体内存也就是书所占的大小来开辟空间,这样其它的也能放下。

在这里插入图片描述
我们就可以选择礼物及它的成员。
在这里插入图片描述

2.4 判断当前机器的大小端

在之间博客中有说明,这里就不过多讲述,有需要的可以查看; link

在这里插入图片描述
之前所写的代码是利用指针来判断的:

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

	return 0;
}

在这里插入图片描述
结果显示的是小端。

-----------------------------------------------------------------------------------------

这次我们使用联合体来判断

int check_sys()
{
	union
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}

int main()
{
	
	if (check_sys() == 1)
		printf("小端\n");
	else
		printf("大端\n");

	return 0;
}

也就是来判断一下u.c存的是0还是1?
在这里插入图片描述
结果和上面一样,是小端存储
在这里插入图片描述

3. 枚举

3.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,当然在声明枚举类型的时候也可以赋初值。

来看看日期的取值:
在这里插入图片描述
也就是:默认从0开始,依次递增1,一直到6。

当然在声明枚举类型的时候也可以赋初值。

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

int main()
{
    printf("%d %d %d\n", RED, GREEN, BLUE);

    return 0;
}

在这里插入图片描述

3.2 枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:

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

举个例子:实现一个简单计算器
我们就能将加减乘除设置成枚举类型,这样在主函数中进行对应的操作时就会知道就行的是哪中计算。
这里只是简单举个例子说明一下枚举的优点,具体的函数大家可以自行修改。

void menu()
{
	printf("*********************\n");
	printf("*** 1.add  2.sub  ***\n");
	printf("*** 3.mul  4.div  ***\n");
	printf("*** 0.exit        ***\n");
	printf("*********************\n");
}

enum Option
{
	EXIT,//0
	ADD,//1
	SUB,//2
	MUL,//3
	DIV//4
};
int Add(int a, int b)
{
	return a + b;
}

int Sub(int a, int b)
{
	return a - b;
}

int Mul(int a, int b)
{
	return a * b;
}

int Div(int a, int b)
{
	return a / b;
}

int main()
{
	int input = 0;
	int a = 0;
	int b = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		scanf("%d %d", &a,&b);
		switch (input)
		{
		case ADD:
			Add(a, b);
			break;

		case SUB:
			Sub(a, b);
			break;

		case MUL:
			Mul(a, b);
			break;

		case DIV:
			Div(a, b);
			break;

		default:
			break;
		}
	} while (input);

	return 0;
}

3.3 枚举类型的使用

enum Color//颜色
{
    RED = 1,
    GREEN = 2,
    BLUE = 4
};

int main()
{

    enum Color clr = GREEN;//使用枚举常量给枚举变量赋值
    enum Color clr2 = 2;
    printf("%d\n", sizeof(clr));//4
    return 0;
}

在这里插入图片描述

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

有错误请指出,大家一起进步!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

利用Spark构建房价分析与推荐系统:基于58同城数据的大数据实践

利用Spark构建房价分析与推荐系统&#xff1a;基于58同城数据的大数据实践 基于Spark的房价数据分析预测推荐系统引言技术栈功能概述项目实现1. 数据爬取与处理2. 大数据分析与可视化3. 房价预测模型4. 协同过滤推荐系统5. Web应用开发6. 数据管理与用户管理 总结与展望 基于Sp…

常见的Web攻击手段分析总结,实战案例:通过 X-Forwarded-Host 的密码重置令牌泄漏

常见的Web攻击手段分析总结,实战案例:通过 X-Forwarded-Host 的密码重置令牌泄漏。 常见的 Web 攻击手段主要有 XSS 攻击、CSRF 攻击、SQL 注入攻击、DDos 攻击、文件漏洞攻击等。这几种攻击方式的防护手段并不复杂,却还是有很多企业遭受了该攻击,朔源到头,还是因为人为的…

【实时绘画】krita + comfyUI 实时绘画 儿童海报

1&#xff1a;打开comfyUI 2: 打开krita 打开 cd custom_nodes 输入命令 安装控件 git clone https://github.com/Acly/comfyui-tooling-nodes.git

Gamma分布

分布的概率密度为&#xff1a; 其中参数 分布的数学期望等于&#xff0c;方差等于。

java:用ClassLoader将文件转化为输入流

代码示例&#xff1a; package com.thb;import java.io.IOException; import java.io.InputStream;public class Demo4 {public static void main(String[] args) throws IOException {String resource "com/thb/test.properties";// 获得ClassLoaderClassLoader c…

大数据HCIE成神之路之数据预处理(3)——数值离散化

数值离散化 1.1 无监督连续变量的离散化 – 聚类划分1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析 1.1.2 实验思路1.1.3 实验操作步骤1.1.4 结果验证 1.2 无监督连续变量的离散化 – 等宽划分1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实…

用户管理第2节课-idea 2023.2 后端--删除表,从零开始

一、鱼皮清空model文件夹下 二、鱼皮清空mapper文件夹下 三、删除 test 测试类下的部分代码 3.1删除SampleTest 3.2删除部分代码 UserCenterApplicationTests

自动化测试|Eolink Apikit 如何保存、使用测试用例

测试用例是测试过程中很重要的一类文档&#xff0c;它是测试工作的核心&#xff0c;是一组在测试时输入和输出的标准&#xff0c;是软件需求的具体对照。 测试用例可以帮助测试人员理清测试思路&#xff0c;确保测试覆盖率&#xff0c;发现需求漏洞&#xff0c;提高软件质量&a…

VC++ MinGW编译器将图片、字体等资源文件编译进程序和使用

Mingw使用附带的windres.exe可以将资源文件编译成.o文件, 之后与其他目标文件一起g++.exe链接生成程序 为了方便,使用mingw编译器版本的codeblock编写程序 用位图资源作为例子,新建一个空项目,在项目下新建一个资源文件,resource.rc,一个cpp文件main.cpp,一个头文件reso…

YOLOv8轻量化模型:模型轻量化创新 | MobileNetV3结合轻量级MLCA模块

💡💡💡本文解决什么问题:MobileNetV3结合轻量级的 Mixed Local Channel Attention (MLCA) 模块,实现轻量化 1.MLCA原理介绍 论文:https://www.sciencedirect.com/science/article/abs/pii/S0952197623006267 摘要:本项目介绍了一种轻量级的 Mixed Local Channel At…

IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -SpringMVC搭建框架

第一章 初识SpringMVC 1.1 SpringMVC概述 SpringMVC是Spring子框架 SpringMVC是Spring 为**【展现层|表示层|表述层|控制层】**提供的基于 MVC 设计理念的优秀的 Web 框架&#xff0c;是目前最主流的MVC 框架。 SpringMVC是非侵入式&#xff1a;可以使用注解让普通java对象&…

2万字揭秘阿里巴巴数据治理平台建设经验(上),附推荐系统完整源码

原文链接 https://mp.weixin.qq.com/s?__bizMjM5MjA0OTYwNQ&mid2247484210&idx1&sn5ceffbba79553219b792e2fcfb9c6789&chksma6ad739891dafa8eeabcde82ed24f04d9ffbbb837137fe7c1c72b38c986b38aa83f0c593e02a&token909431872&langzh_CN#rd 本文从七个…

Qt之判断一个点是否在多边形内部(射线法)

算法思想: 以被测点Q为端点,向任意方向作射线(一般水平向右作射线),统计该射线与多边形的交点数。如果为奇数,Q在多边形内;如果为偶数,Q在多边形外。计数的时候会有一些特殊情况。这种方法适用于任意多边形,不需要考虑精度误差和多边形点给出的顺序,时间复杂度为O(n)…

C# NPOI导出datatable----Excel模板画图表

1、创建Excel模板 2、安装NPOI管理包 3、创建工作簿 &#xff08;XLSX和XLS步骤一样&#xff0c;以XLS为例&#xff09; IWorkbook workbook null; string time DateTime.Now.ToString("yyyyMMddHHmmss"); string excelTempPath Application.StartupPath "…

VScode安装C/C++编译器步骤

一、安装C/C插件 二、安装 MinGW-w64 工具链 使用国内源 git clone https://gitee.com/cuihongxi/ubuntu2-mac.git 下载后进入到VScode文件夹下&#xff0c;点击msys2-x86_64-20231026.exe进行安装 完成后&#xff0c;确保选中“立即运行 MSYS2”框&#xff0c;然后选择“完…

比特币和区块链并非游离在法律之外

​​发表时间&#xff1a;2023年12月01日 近年来&#xff0c;围绕区块链监管的讨论&#xff0c;已经成为政策制定者、行业领袖和区块链爱好者之间越来越重要的话题。随着各国政府在促进创新和确保消费者保护之间寻求着平衡&#xff0c;有关区块链监管的持续讨论反映出这项变革性…

ssm445基于SSM的学生宿舍管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本学生宿舍管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

HDFS NFS Gateway(环境配置,超级详细!!)

HDFS NFS Gateway简介: ​ HDFS NFS Gateway是Hadoop Distributed File System&#xff08;HDFS&#xff09;中的一个组件&#xff0c;它允许客户端通过NFS&#xff08;Network File System&#xff0c;网络文件系统&#xff09;与HDFS进行交互。具体来说&#xff0c;HDFS NFS…

管理类联考——数学——真题篇——按知识分类——代数——数列

【等差数列 ⟹ \Longrightarrow ⟹ 通项公式&#xff1a; a n a 1 ( n − 1 ) d a m ( n − m ) d n d a 1 − d A n B a_n a_1(n-1)d a_m(n-m)dnda_1-dAnB an​a1​(n−1)dam​(n−m)dnda1​−dAnB ⟹ \Longrightarrow ⟹ A d &#xff0c; B a 1 − d Ad&#x…

【CSS @property】CSS自定义属性说明与demo

CSS property property - CSS: Cascading Style Sheets | MDN At 规则 - CSS&#xff1a;层叠样式表 | MDN Custom properties (–*): CSS variables - CSS: Cascading Style Sheets | MDN CSS Houdini - Developer guides | MDN &#x1f4da; 什么是property? property CSS…