自定义类型:联合和枚举

devtools/2024/9/21 7:55:23/

一 ,联合体类型的声明

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

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

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

 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++中会报错


http://www.ppmy.cn/devtools/114882.html

相关文章

mysql5.7.44安装教程

mysql5.7.44安装教程 1.windows 二进制压缩包从MySQL官网下载即可。 2.解压后,在根目录下创建my.ini文件 [mysql] # 设置 mysql 客户端默认字符集 default-character-setutf8 [mysqld] #设置 3306 端口 port 3306 # 设置 mysql 的安装目录 basedir …

VMware安装rustdesk服务器

一、准备 首先准备服务器镜像:22.04 虚拟机硬件配置选1G RAM 20G ROM就行 二、虚拟机安装过程 安装过程中选最小体积安装,并勾选安装SSH 安装完成后在SSH工具中连接(步骤可视实际情况跳过): //需要先连接外网 1.安…

list(二) (list模拟实现)

首先进行大框架 先写基本的结点类 有data next prev template<class T>class ListNode//或者使用struct 就不用在写public声明公有{public://这里不仅仅是成员函数 成员变量也要公有化 ListNode<T>* _next;ListNode<T>* _prev;T _data;}之后是链表list类…

【实践】应用访问Redis突然超时怎么处理?

目录标题 问题描述分析过程查看监控数据系统监控指标JVM监控指标Redis监控指标分析应用异常单机异常规律集群异常规律统计超时的key 初步结论验证结论访问Redis链路slowlogRedis单节点info all定位redis节点定位异常keybigkeystcpdump定位大key影响 经验总结 问题描述 某产品线…

【论文笔记】Are Large Kernels Better Teacheres than Transformers for ConvNets

Abstract 本文提出蒸馏中小核ConvNet做学生时&#xff0c;与Transformer相比&#xff0c;大核ConvNet因其高效的卷积操作和紧凑的权重共享&#xff0c;使得其做教师效果更好&#xff0c;更适合资源受限的应用。 用蒸馏从Transformers蒸到小核ConvNet的效果并不好&#xff0c;原…

Unity 设计模式 之 结构型模式 -【适配器模式】【桥接模式】 【组合模式】

Unity 设计模式 之 结构型模式 -【适配器模式】【桥接模式】 【组合模式】 目录 Unity 设计模式 之 结构型模式 -【适配器模式】【桥接模式】 【组合模式】 一、简单介绍 二、适配器模式 (Adapter Pattern) 1、什么时候使用适配器模式 2、使用适配器模式的好处 3、适配器…

Android中的四大组件

Android中的四大组件是Android应用开发中的基石&#xff0c;它们分别是Activity、Service、BroadcastReceiver和ContentProvider。这四个组件各自承担着不同的角色和功能&#xff0c;共同构成了Android应用程序的骨架。下面将详细阐述这四大组件的作用及其特点。 1. Activity&…

基于STM32设计的路灯故障定位系统(微信小程序)(229)

文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】ESP8266工作模式配置1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】项目背景【5】摘要1.4 开发工具的选择【1】设备端开发【2…