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

认识联合体和枚举

目录

一.联合体

1.联合体的声明

2.联合体的特点

(一)内存共享

(二)大小等于最大成员的大小

另一特殊情况:

(三)一次只能使用一个成员

3.联合体相比较于结构体

(一)内存分配

(二)使用方式

(三)内存布局对比

(四)总结

二.枚举

1.特点

2.语法

3.特殊情况

(一)枚举类型的隐式转换

(二)枚举的作用域

(三)缺乏类型安全

(四)枚举的拓展


一.联合体

1.联合体的声明

联合体(Union) 是一种特殊的用户自定义数据类型,它允许在同一内存位置存储不同类型的数据,但同时只能存储其中一个成员。联合体的所有成员共享相同的内存空间,因此联合体的大小等于其最大成员的大小

我们来看一下简单定义,有些类似于结构体.。

#include<stdio.h>
union un {int age;char i;
};
int main() {return 0;
}

虽然说结构上有些类似于结构体,但是看特点的话,他两各不相同,各有所长。

2.联合体的特点

(一)内存共享

联合体的所有成员共享同一块内存地址。意味着不论联合体有多少成员,它们都会使用同一个存储空间。只有一个成员可以在同一时刻存储有效数据。

优点:这种特性使联合体节省内存,特别适合多个数据不会同时使用的场景。

我们来看一个例子:

#include<stdio.h>
union un {int age;char i;
};
int main() {union un u = { 0 };u.age = 0x11223344;u.i = 0x55;return 0;
}

我们按F10进入逐过程:

查看内存:可以看到u.i的0x55覆盖了u.age的44

可以说明他们的内存是共享的!!!

(二)大小等于最大成员的大小

联合体的大小等于其最大成员的大小。虽然它可以有多个成员,但只会根据其中最大成员的大小来分配内存。

我们看一下例子:

#include<stdio.h>
union un {int age;char i;
};
int main() {union un u = { 0 };//计算一下联合体的大小printf("%zd", sizeof(u));return 0;
}

结果是:

解释:int四个字节,char一个字节,显然最大的是四个字节。联合体的大小即最大成员的大小

另一特殊情况:

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

看一例子:

#include<stdio.h>
union un {char name[10];int age;
};
int main() {union un u = { 0 };printf("%zd", sizeof(u));return 0;
}

我们看一下结果:

可以看到联合体的大小并不是最大成员的大小10(char1个字节,1*10),是12(最大对齐数4,4的整数倍)

这里10个char类型和int类型就已经占用14个字节了,但是结果是12个字节,所以这里也能证明联合体的特点内存共享。

(三)一次只能使用一个成员

联合体(union)的特性是一次只能有效使用一个成员,因为所有成员共享同一块内存。当你向一个成员赋值时,之前赋值的其他成员数据会被覆盖。

其实也就是因为另一个特性内存共享导致的

#include <stdio.h>
#include <string.h>union MyUnion {int i;float f;char str[20];
};int main() {union MyUnion u;// 设置整数值u.i = 42;printf("设置整数后: u.i = %d\n", u.i);// 设置浮点数值,覆盖整数值u.f = 3.14;printf("设置浮点型之后: u.f = %.2f\n", u.f);// 整数值被覆盖,无法正常读取printf("u.i (设置浮点型之后) = %d (corrupted)\n", u.i);// 设置字符串,覆盖浮点数值strcpy(u.str, "Hello");printf("设置字符串后: u.str = %s\n", u.str);// 浮点数值被覆盖,无法正常读取printf("u.f (设置字符串后) = %.2f (corrupted)\n", u.f);return 0;
}

结果:

3.联合体相比较于结构体

(一)内存分配

结构体:

  • 结构体中的每个成员都有自己独立的内存空间。
  • 结构体的总大小等于所有成员大小的总和(加上可能的内存对齐)。
  • 成员的内存布局是顺序的,成员之间不会共享内存

联合体:

  • 联合体中的所有成员共享同一块内存。
  • 联合体的总大小等于其中最大成员的大小。
  • 只能同时使用一个成员,存入一个成员的值会覆盖其他成员。

(二)使用方式

  • 结构体

    • 结构体可以同时使用多个成员。每个成员都有独立的存储空间,互不干扰。
    • 适合用于描述包含多个相关数据的复杂对象。

(三)内存布局对比

 看看这两个代码内存的占用

  

我们看一下内存分布图:

(四)总结

特性结构体联合体
内存分配每个成员都有独立内存,大小为所有成员之和。所有成员共享同一块内存,大小为最大成员。
使用多个成员可以同时使用多个成员。一次只能使用一个成员,修改会覆盖其他成员。
适用场景同时需要存储和操作多种数据类型。不同时间只需使用一种数据类型,节省内存。
访问速度各成员独立访问,互不影响。需要判断当前存储的成员类型,可能增加复杂度。

二.枚举

枚举(enum)是一种用户自定义的数据类型,它由一组具名的常量组成。枚举常用于表示一组相关的离散值,赋予这些值易于理解的名称,增强代码的可读性和维护性。

1.特点

  • 命名常量:枚举为一组常量提供了有意义的名字,使代码更具可读性。
  • 整数值:在大多数编程语言中,枚举中的每个常量值都与一个整数值对应,通常从 0 开始递增,除非显式指定。
  • 类型安全:枚举类型可以帮助确保在代码中只能使用有效的枚举常量,而不会混用其他不相关的值。

2.语法

看个例子:

#include <stdio.h>enum Weekday {SUNDAY,    // 默认值为 0MONDAY,    // 1TUESDAY,   // 2WEDNESDAY, // 3THURSDAY,  // 4FRIDAY,    // 5SATURDAY   // 6
};int main() {enum Weekday today;today = WEDNESDAY;if (today == WEDNESDAY) {printf("Today is Wednesday!\n");}return 0;
}

结果如图:

第二个例子(如果对某个成员赋值,后续成员会从该值开始递增):

enum EnumName {ENUM_VALUE1,      //0ENUM_VALUE2,      //1ENUM_VALUE3 = 10, // 可以显式指定值ENUM_VALUE4       // 之后的值会递增,即11
};

枚举中的每个常量值都与一个整数值对应,通常从 0 开始递增,除非显式指定。

ps:要注意每个成员用","隔开

3.特殊情况

(一)枚举类型的隐式转换

枚举类型在 C 语言中实际上是整型,可能导致与整型混淆。比如,可以将整型值赋给枚举类型:

enum Weekday { SUNDAY, MONDAY, TUESDAY };
enum Weekday day = 3; // 这是合法的,但不安全

(二)枚举的作用域

在 C 语言中,枚举的常量在枚举定义的作用域内可见,但不会限定在枚举类型内部:

enum Colors { RED, GREEN, BLUE };
int color = RED; // 合法,因为 RED 在全局作用域中可见

(三)缺乏类型安全

尽管枚举在一定程度上提供了类型安全,但它们的整型本质仍然使得在比较或赋值时存在风险。例如,可以将一个枚举类型的变量赋值为与之不相关的整数值,这可能导致逻辑错误:

enum Direction { NORTH, SOUTH, EAST, WEST };
enum Direction dir = 10; // 合法,但不正确

(四)枚举的拓展

在 C 语言中,枚举类型一旦定义就不能被扩展或修改。它的值和成员是固定的。因此,枚举不能如同其他数据类型那样进行动态修改。

相关文章:

  • 从零开发操作系统
  • PostgreSQL的扩展(extensions)-常用的扩展-pgstattuple
  • 鸿蒙开发(NEXT/API 12)【硬件(获取智慧出行连接状态)】车载系统
  • 通过人工智能AI大模型定制的完美旅游行程
  • 双指针---(部分地更新)
  • 基于JAVA springboot+mybatis智慧生活分享平台设计和实现
  • CS 工作笔记:SmartEdit 里创建的是 CMS Component
  • 调用飞书接口导入供应商bug
  • Vue3 工具函数(总结)
  • 大数据处理从零开始————8.基于Java构建WordCount项目
  • ①EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器
  • [Linux]进程管理指令
  • 第十一届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(大学组)
  • 第五章 linux实战-挖矿 二
  • Azure OpenAI检索增强微调:使用 GPT-4o 对 GPT-4o mini 进行微调,以适应特定领域的应用
  • 【Amaple教程】5. 插件
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • egg(89)--egg之redis的发布和订阅
  • es6--symbol
  • javascript数组去重/查找/插入/删除
  • Java小白进阶笔记(3)-初级面向对象
  • Redux系列x:源码分析
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Spring Cloud Feign的两种使用姿势
  • Xmanager 远程桌面 CentOS 7
  • 第2章 网络文档
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 给初学者:JavaScript 中数组操作注意点
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 码农张的Bug人生 - 初来乍到
  • 前端
  • 使用Swoole加速Laravel(正式环境中)
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 微服务入门【系列视频课程】
  • 为视图添加丝滑的水波纹
  • 移动端 h5开发相关内容总结(三)
  • 转载:[译] 内容加速黑科技趣谈
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 如何在招聘中考核.NET架构师
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (10)STL算法之搜索(二) 二分查找
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (3)llvm ir转换过程
  • (4)logging(日志模块)
  • (done) Go 语言:三种多文件协作方式
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (ros//EnvironmentVariables)ros环境变量
  • (附源码)ssm码农论坛 毕业设计 231126
  • (十) 初识 Docker file
  • (一)RocketMQ初步认识
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径