当前位置: 首页 > news >正文

自定义类型:联合和枚举

一 ,联合体类型的声明

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

但是与结构体不同的是 : 编译器只为联合体成员中的最大成员分配足够的内存空间。 联合体的特点是所有成员共用一块内存空间。所以联合体 也称  ===>    共用体

那也就意味着联合体其中一个成员赋值,其他成员的值也跟着变化

 union tag

{

                member-list;

}variable - list ;  

//联合体类型声明
union U
{char c;int n;
};
int main()
{//联合体类型定义union U un = { 0 };//计算联合体变量的大小printf("%zd\n", sizeof(un));//4return 0;
}

 输出结果 : 4  

并不是 5 也不是 8 ;这就与联合体成员在内存中的分布有关;

二 ,联合体的特点

2.1 联合体的内存布局

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

union U
{char c;int n;
};
int main()
{union U u = { 0 };printf("联合体大小 : %zd\n", sizeof(u));printf("%p\n", &u);printf("%p\n", &u.c);printf("%p\n", &u.n);return 0;
}

 那就意味这在这块联合体的内存空间中,变量分布是:

初始化数值,进入调试,查看内存情况验证

 经过分析可以画出  ,  u 的内存布局图

2.2 联合体与结构体的对比 

struct S
{char c;int n;
};union U
{char c;int n;
};
int main()
{printf("S : %zd\n", sizeof(struct S));printf("U : %zd\n", sizeof(union U));return 0;
}

 联合体与结构体的内存图:

三 ,联合体大小的计算

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

例题一: 

union u
{char c[5];int n;
}un1;
int main()
{printf("%zd\n", sizeof(un1));return 0;
}

 例题二:

union u
{short c[7];int i;
}n1;
int main()
{printf("%zd\n", sizeof(n1));return 0;
}

 

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

比方说,有个活动,可以进行礼品兑换,可进行兑换中有三种商品:图书 ,杯子 ,衬衫。

每一种商品都有:库存量 ,价格 ,商品类型 和 商品类型相关的其他信息

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

进而就会考虑到使用结构体 把数据统统放进去,可这样会对空间造成一定的浪费。结构中包含了所有的礼品的各种属性,但是只有部分属性信息是常用的,

比方说:商品是图书,就不需要 design , colors , sizies 。

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

所以可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合起来,这样就可以在一定程度上节省了空间。 

struct gift_list
{//公共属性int stock_number;//库存量double price;//定价int item_type;//商品类型union{struct {char title[20];//书名char author;//作者int num_pages;//页数}book;struct{char design[30];//设计}mug;struct{char design[30];//设计int color;//颜色int sizes;//尺寸}shirt;}item;
};

 需要用到谁,就可以开辟谁的空间。可以使用匿名结构体 和 匿名联合体 ,因为只需要用到成员就好了,不需要用到类型。

2.3 练习

写一个程序,判断当前机器是小端还是大端? 

//法一
int main()
{int a = 1;//0x00 00 00 01if (*(char*)&a == 1)printf("小端\n");elseprintf("大端\n");return 0;
}//法二
int check_sys()
{int a = 1;if (*(char*)&a == 1)return 1;elsereturn 0;
}
int main()
{int ret = check_sys();if (ret == 1)printf("小端\n");elseprintf("大端\n");return 0;
}//法三 -- 联合体
int check_sys()
{union{char c;int n;}n;n.n = 1;return n.c;
}
int main()
{int ret = check_sys();if (ret == 1)printf("小端\n");elseprintf("大端\n");return 0;
}

四 ,枚举类型的声明

 枚举顾名思义就是      一 一 列举   (列举可能   有限  的值)

比如:

  • 一周中周一到周日 有限7天
  • 性别:男 , 女 ,保密
  • 月份有12个月
  • 三原色:红绿蓝

这些数据的表示就可以使用枚举

举例: 

enum Day//星期
{Mon,Tues,wed,Thur,Fri,Sat,sun
};enum Sex//性别
{MALE,FEMALE,SACRET
};enum Color//颜色
{RED,GREEN,BULE
};

 书写格式:

  1.  定义的 enum Day ,enum Sex , enum Color 都是枚举类型
  2. { } 中的内容是枚举类型的可能值 , 也叫枚举常量
  3. 这些枚举常量都是有值的 , 默认从0开始 , 依次递增 1 ,枚举常量是不可以被修改的,但是可以赋初始值。

1.三个都可以各自赋初始值 

 2. 仅对第一个常量赋值 , 其他常量依次增1

3.对中间的常量赋值 , 第一个常量会默认为0 , 往后依次增加 1 到 赋值的中间常量 , 中间常量往后 , 以中间常量的值为起始,依次增加 1 ;

五 ,枚举类型的优点

 为什么要使用枚举?

用#define 定义常量   或者说 在函数里创建一个变量 int sex = 0 // 1  2

也都可以表示男 , 女 这些值

枚举的优点

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

六 ,枚举类型的使用

enum color//颜色
{red,green,bule
};int main()
{enum color crl = green;return 0;
}

 使用枚举常量给枚举变量赋值

 注意 : 在C语言中可以拿整数给枚举变量赋值,因为C中的类型检查不够严格 , 但是在C++中会报错

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 经典sql题(二)求连续登录最多天数用户
  • 【百日算法计划】:每日一题,见证成长(018)
  • Ubuntu 22.04 源码下载的几种方法
  • 项目中遇到的问题
  • 【论文阅读】Face2Diffusion for Fast and Editable Face Personalization
  • 搜索引擎onesearch3实现解释和升级到Elasticsearch v8系列(五)-聚合
  • GitHub每日最火火火项目(9.20)
  • 【简单点】docker如何部署tomcat
  • 线程池的类型
  • 掌握顶会流量密码!“Mamba+CNN”双热点组合!轻松找到创新点!
  • EP21 Promise封装request请求
  • Java企业面试题3
  • 数据结构—单链表
  • 让医院更智慧,让决策更容易
  • LeetCode_sql_day30(1264.页面推荐)
  • 【译】理解JavaScript:new 关键字
  • 4个实用的微服务测试策略
  • Angular 响应式表单之下拉框
  • ES6系列(二)变量的解构赋值
  • Fundebug计费标准解释:事件数是如何定义的?
  • JS基础之数据类型、对象、原型、原型链、继承
  • JS题目及答案整理
  • Netty 4.1 源代码学习:线程模型
  • nodejs:开发并发布一个nodejs包
  • passportjs 源码分析
  • PHP的Ev教程三(Periodic watcher)
  • Terraform入门 - 1. 安装Terraform
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 从重复到重用
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 漂亮刷新控件-iOS
  • 七牛云假注销小指南
  • 前端知识点整理(待续)
  • 少走弯路,给Java 1~5 年程序员的建议
  • 整理一些计算机基础知识!
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​数据结构之初始二叉树(3)
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #define与typedef区别
  • #Ubuntu(修改root信息)
  • $.ajax()参数及用法
  • (175)FPGA门控时钟技术
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (八)Spring源码解析:Spring MVC
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • .gitignore文件---让git自动忽略指定文件
  • .NET BackgroundWorker
  • .net core 6 redis操作类
  • .Net MVC + EF搭建学生管理系统
  • .NET Project Open Day(2011.11.13)
  • .NET 常见的偏门问题
  • .Net(C#)自定义WinForm控件之小结篇