【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 1int i;//4       4 8 4
};union Un2
{short c[7];//14   2   8  2int i;//4         4   8  4
};int main()
{printf("%d\n", sizeof(union Un1));//8printf("%d\n", sizeof(union Un2));//16return 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");elseprintf("大端\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,//0ADD,//1SUB,//2MUL,//3DIV//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));//4return 0;
}

在这里插入图片描述

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

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

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

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

相关文章

加速度|SHOPFA商城如何与阿里云短信融合

商城系统上线之后&#xff0c;需要与短信平台进行融合&#xff0c;当客户下完订单之后&#xff0c;能够接收到支付短信、发货短信、配送短信等进度提示信息。阿里云短信&#xff0c;作为国内领先的短信平台&#xff0c;隶属于阿里云计算有限公司&#xff0c;背后强大的研发团队…

苏宁易购商品详情API:电商实时数据

一、引言 在当前的电商行业中&#xff0c;数据是最为宝贵的资源之一。如何获取实时、准确的数据&#xff0c;对于电商业务的运营和优化至关重要。作为中国领先的电商平台之一&#xff0c;苏宁易购提供了丰富的API接口&#xff0c;其中包括商品详情API&#xff0c;以便第三方开…

flutter开发实战-第一帧布局完成回调实现

flutter开发实战-第一帧布局完成回调实现 在开发中&#xff0c;我们有时候需要在第一帧布局完成后调用一些相关的方法。这里记录一下是实现过程。 Flutter中有多种不同的Binding&#xff0c;每种Binding都负责不同的功能。下面是Flutter中常见的Binding&#xff1a; 这里简单…

oracle vm virtualBox虚拟机网卡设置

一、桥接模式 1、桥接模式自动分配IP 通过dns自动分配Ip方式、重启服务器可能会出现IP变动的情况。 选中虚拟机--设置--网络&#xff0c;链接方式选择“桥接网卡”&#xff0c;界面名称选择“需要桥接的网卡名称” 不清楚的可以在宿主机网络设置查看&#xff08;需要桥接哪…

JVM调优小结

JVM常见工具介绍 jinfo(查看配置信息) 查看Java应用程序配置参数或者JVM系统属性&#xff0c;相关命令详情我们可以使用-help或者man命令查看&#xff0c;如下所示: [rootxxxxxtmp]# jinfo -help Usage:jinfo [option] <pid>(to connect to running process)jinfo [op…

一键在线获取APP公钥、包名、签名及备案信息方法介绍

​ 目录 一键在线获取APP公钥、包名、签名及备案信息方法介绍 摘要 引言 一键获取APP包信息 操作步骤 ​编辑 解析报告 总结 致谢 关键词 参考资料 声明 摘要 本文介绍了一款在线APP解析工具&#xff0c;可以一键获取APP的公钥、包名、签名等基础信息&#xff0c;…

3D材质编辑器

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 GLTF 编辑器 -NSDT 支持GLTF/GLB模型的基本材质的编辑修改&#xff0…

autostart 应用自启动配置

linux 通用配置 1. 编写 desktop 文件 # cat xxx.desktop [Desktop Entry] TypeApplication Exec/xxx/app //应用程序 2. 将 xxx.desktop 文件拷贝到 /etc/xdg/autostart/ 下面 # cp xxx.desktop /etc/xdg/autostart/

Linux Centos 配置 Docker 国内镜像加速

在使用 Docker 进行容器化部署时&#xff0c;由于国外的 Docker 镜像源速度较慢&#xff0c;我们可以配置 Docker 使用国内的镜像加速器&#xff0c;以提高下载和部署的效率。本文将介绍如何在 CentOS 系统上配置 Docker 使用国内镜像加速。 步骤一&#xff1a;安装 Docker 首…

手机怎么设置每年公历或农历生日提醒?生日提醒设置小妙招

生日是一个人在一年中比较特殊的日子之一&#xff0c;人们通常希望能够在这一天得到亲朋好友的祝福和庆祝。然而&#xff0c;随着人们生活节奏的加快&#xff0c;很多人表示自己很容易忘记他人的生日&#xff0c;导致不能够及时送出祝福和礼物。如果经常忘记亲朋好友的生日&…

搭建动态网站之——基于Redhat8.6搭建Discuz论坛

目录 一、动态网站与静态网站区别 1、提供用户互动接口的动态网站 2、搭建动态网站的需求&#xff1a; 二、搭建步骤 第一步&#xff1a;www服务器配置 第二步;编辑网页文件 第三步&#xff1a;使用xftp 将Discuz包传到/discuz解压 1、将Discuz包移动到/discuz 2、解压…

hive企业级调优策略之数据倾斜

测试所用到的数据参考&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/m0_52606060/article/details/135080511 本教程的计算环境为Hive on MR。计算资源的调整主要包括Yarn和MR。 数据倾斜概述 数据倾斜问题&#xff0c;通常是指参与计算的数据分布不均&#xff0…