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

联合体与枚举:面试官问我“状态机怎么设计”,靠的就是这两个

上篇聊了struct的内存对齐,有人后台说想看struct和class的区别详解。别急,后面会专门写。

今天聊两个面试里容易被忽视、但实际工程中特别有用的东西:联合体union枚举enum

为什么放一起讲?因为在机器人开发里,这俩经常搭档出现——特别是设计状态机的时候。

讲个面试故事。

去年面试一个候选人,简历上写着"设计过机器人状态机"。我问他:"你的状态机是怎么实现的?"

他说用了一堆if-else,状态用int表示,0是空闲,1是运行,2是错误……

我问他:"如果别人接手你的代码,看到if (state == 3),他知道3是什么意思吗?"

他愣了一下,说:"我写了注释的。"

我又问:"如果状态变了,比如加了一个新状态4,你怎么保证所有用到状态的地方都更新了?"

他没答上来。

讲真,这种问题我太常见了。不是不会写状态机,而是没有用对工具。如果他用的是enum,上面两个问题都不存在。

联合体union:几个变量共享同一块内存

先说union,因为这个面试考得比enum多。

union是什么?它把几个不同类型的变量放在同一块内存上,同一时刻只有一个变量是有效的。

和struct最大的区别:struct是每个字段各占各的空间,union是所有字段共用一块空间。

union Data { int i; float f; char c; };

这个union占多少字节?答案是4字节——和最大的字段(int或float)一样大。

而如果是struct,加上内存对齐,至少要12字节。

union的内存模型是这样的:i、f、c三个变量的起始地址完全相同,都是这块4字节内存的开头。你往i写数据,f和c的内容就变了,因为它们读的是同一块内存。

Data d; d.i = 65; cout << d.c << endl; // 输出 'A',因为65是'A'的ASCII码

这种特性在机器人开发里有什么用?

场景一:协议解析。机器人通信协议里,经常有一段原始数据需要按不同类型来解读。比如一个4字节的payload,有时候是int,有时候是float,用union最方便:

union Payload { int32_t int_val; float float_val; uint8_t bytes[4]; };

场景二:节省内存。如果你有一个数组,每个元素可能是不同类型的数据,用union可以省空间。比如一个传感器读数,有时是温度(float),有时是状态码(int),用union只需要占最大类型的空间。

面试的时候,面试官问union,最爱考的就是"union占多少字节"和"union和struct的区别"。记住:union共享内存,大小等于最大字段;struct各占各的,大小等于所有字段加padding。

枚举enum:给状态起个有意义的名字

再说enum。

enum是什么?给一组相关的常量起有意义的名字。

没有enum之前,大家用int或#define表示状态:

#define STATE_IDLE 0 #define STATE_RUNNING 1 #define STATE_ERROR 2

这种写法有两个问题:第一,#define没有作用域,容易命名冲突;第二,编译器不知道这些常量是一组的,没法做类型检查。

用enum就好了:

enum RobotState { STATE_IDLE, STATE_RUNNING, STATE_ERROR };

现在STATE_IDLE、STATE_RUNNING、STATE_ERROR是RobotState类型的值。如果你写RobotState s = 5;,编译器会报警告——因为5不是一个有效的枚举值。

但传统的enum有个坑:它会把枚举值暴露到外层作用域。如果你有两个enum都定义了ERROR,就会冲突。

enum MotorState { IDLE, RUNNING, ERROR }; enum SensorState { IDLE, READY, ERROR }; // 编译错误!ERROR重复定义

所以C++11引入了enum class(强类型枚举):

enum class MotorState { IDLE, RUNNING, ERROR }; enum class SensorState { IDLE, READY, ERROR }; // 没问题 MotorState ms = MotorState::ERROR; SensorState ss = SensorState::ERROR;

现在每个枚举值都在自己的作用域里,不会冲突。而且enum class不能隐式转换成int,更安全。

面试的时候,如果你能主动提到enum class和传统enum的区别,面试官会觉得你对C++11有了解。

联合体+枚举:状态机的经典搭配

回到开头那个面试故事。怎么用union和enum设计一个清晰的状态机?

思路是这样的:用enum表示当前状态,用union存储不同状态下的数据。

enum class RobotState { IDLE, MOVING, SENSING, ERROR }; struct MoveData { double target_x, target_y; double current_speed; }; struct SenseData { float distance; int object_id; }; struct ErrorData { int error_code; char message[64]; }; union StateData { MoveData move; SenseData sense; ErrorData error; }; struct RobotFSM { RobotState state; StateData data; };

这样设计的好处是什么?

第一,状态用enum表示,语义清晰。if (fsm.state == RobotState::MOVING)比if (fsm.state == 1)好读一百倍。

第二,不同状态的数据用union存储,节省内存。MOVING的时候不需要SENSING的数据,它们共用同一块内存。

第三,类型安全。如果用enum class,编译器会帮你检查状态值的合法性。

在机器人开发里,这种模式特别常见。ROS2里的很多消息类型,本质上就是"一个状态标识+不同状态对应的数据"。你用union和enum来理解它,一下就通了。

面试中的常见考法

总结一下,面试中关于union和enum,最爱考这几个点:

union相关:union占多少字节?union和struct的区别?union能不能有构造函数和成员函数?(C++11之后可以,但有限制。)

enum相关:enum和enum class的区别?enum的底层类型是什么?(默认是int,但可以指定。)enum class能不能隐式转成int?(不能。)

综合题:怎么设计一个状态机?这时候你就可以把union和enum的搭配讲出来。

我面试的时候,如果候选人能把状态机设计讲清楚——enum管状态、union管数据、switch-case管转移——我基本就认定这个人有工程思维。

给正在准备面试的你一点建议

union和enum,单独看都不难。难的是把它们组合起来解决实际问题。

我的建议是:

先把union的内存模型搞清楚,能手算union的大小,知道union和struct的区别。然后把enum class的用法练熟,特别是和传统enum的区别。最后,试着自己设计一个简单的状态机——不用复杂,机器人的运动状态就行:空闲、前进、转弯、停止,每个状态带不同的数据。

做完这些,你对union和enum的理解就不只是"课本上的语法"了,而是真正能用到工程设计里的工具。


如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。

「机器人软件开发面试·从入门到精通」连载系列上一篇:第9篇 结构体struct——自定义数据类型的第一步 下一篇预告:第11篇 指针的本质——内存地址的"门牌号"比喻

有任何问题欢迎评论区留言,我会尽量回复。

http://www.jsqmd.com/news/1166471/

相关文章:

  • 2026年成都拍摄产品品牌宣传片视频,背后有哪些不为人知的秘诀? - 企业推荐官
  • 2024年Cocos Creator 3.x免费教程盘点与高效学习路径规划
  • PaLM-E 562B 多模态具身推理实战:3类机器人任务成功率提升 40% 以上
  • 德州家用厨卫支管洗脸盆地漏重油沉淀|打捞|渗水检测 2026 同城抢修靠谱队伍 - 北京金修达天津维修部
  • 分享一套锋哥原创的AI大模型-基于LangChain的智能会议纪要助手系统(Python+FastAPI+Vue3)
  • 7 月古法黄金回收报价更新,实体门店碎金零损耗无损检测 - 讯息早知道
  • 计算机毕业设计之基于ssm的宠物管理系统
  • 用 Go 写一个简单的高性能 HTTP 中间件
  • 黔东南蹲便厨卫支管老旧铸铁管油污淤积/打捞/渗水检测 同城上门评测榜单 (2026 新) - 北京金修达天津维修部
  • Vue3 依赖注入进阶:Symbol 与 InjectionKey 的 2 个 TypeScript 最佳实践
  • WechatBakTool:构建个人数字资产主权管理的系统化框架
  • 2026 武汉香奈儿回收全渠道实测|各区门店走访 + 包包估价避坑完整实操指南 - 奢侈品回收机构参考
  • 帝舵中国官方售后服务中心|地址及服务电话权威信息公告(2026年7月更新) - 帝舵中国官方服务中心
  • 工业信号干扰解决方案:FOD4216光耦与STM32抗噪设计
  • Jenkinsfile才是CI/CD的起点:从自由风格到声明式流水线
  • 华为全家桶到底值不值,对比其他品牌看生态优势在哪
  • 2026年物联网无线通信适配方案选型实用推荐指南 - 招财兔数字员工
  • Midjourney所有公开模型版本完整谱系图(2022.3–2024.6),含训练数据量、参数量估算、LoRA支持状态及官方弃用倒计时——仅限本周开放下载(附SHA256校验码)
  • 2026年7月最新宁波万国官方售后客服电话及服务网点地址查询 - 万国中国官方服务中心
  • 2026年金属管材切割机行业选型应用白皮书 - 招财兔数字员工
  • AI落地实战:从技术鸿沟到工作流重构的行业变革
  • 好消息,新用户福利来啦,千问新用户福利怎么领取8元优惠券?附最新口令:千问新用户专属853226
  • 2026年广州SCMP考试时间怎么安排|众智商学院 - 众智商学院职业教育
  • 终极指南:3步快速解密Widevine DRM加密视频的完整方案
  • PMBOK 第七版 开发方法选择:3大维度12个因素实战决策树
  • 2026东莞发明专利代办服务机构行业观察|科创企业服务能力客观测评 - 小马财税
  • 2026武汉香奈儿回收行情解析|包包高价变现实操攻略 - 奢侈品回收机构参考
  • 国有生产集团薪酬改革:北京华恒智信破解公平性难题
  • Honey Select 2完整汉化与增强补丁:10分钟让游戏焕然一新的终极指南
  • Claude 中转站长期使用指南:为什么稳定调用比低价更重要