恰如其分地撰写出枚举类型能够促使你所编写的C语言代码在可读性方面实现一个层次的提升。为数众多的初学者因嫌其繁琐而径直去书写数字然而在历经三个月之后连他们自身都无法明晰那段逻辑究竟是什么。而当进行调试之时则更是犹如一场灾难。枚举实际上就是为整数赋予相应的名字将那些宛如魔法般的数字转变成为具备实际意义的单词如此这般的一种投入绝对是极为合算的。从零开始认识枚举// 枚举定义 // enum_name: 枚举名称 // member_name: 成员名称 enum { , , };其实枚举的写法是挺简单的用enum关键字去定义一个类型在花括号里把所有可能的取值给列出来并且每个取值都对应着一个名字就像这样子比如enum Weekday { MON, TUE, WED, THU, FRI, SAT, SUN }; 如此一来就创建了一个关于星期几的类型嗯在定义完之后呢就能够用Weekday作为类型去声明变量就好比enum Weekday today MON; 然后代码一下子就变得如同英文句子那般好读了的。编译器对待枚举之际会给每个名字赋予一个整数值倘若不人工去指定默认情况下依序从0启程递增MON是0TUE为1依此类推你也能够在中途定出某个值像把SAT订为5后续的SUN会自行变成6这种自动分配机制省却了手动管理常量的繁杂还规避了重复定义的状况。枚举的底层存储原理在C语言底层枚举是整数编译器会将枚举名字替换为对应的整数值运行时全然不知有枚举类型枚举变量占用内存大小与int相同多为4个字节这表明能把枚举变量直接当作整数使用进行加减乘除均可然而如此做会失去类型检查的保障。// 举例说明 enum COLOR { COLOR_RED 0, COLOR_GREEN, COLOR_BLUE, }; COLOR color COLOR_RED; printf(color %d\n, color); // color 0 // 使用typedef关键字进行类型定义 typedef enum COLOR MY_COLOR; MY_COLOR my_color COLOR_GREEN; printf(my_color %d\n, my_color); // my_color 1因枚举本质上是整数故而它能够与int类型相互进行赋值且不会报错int a MON如此书写是全然合法的a会获取到0反之enum Weekday day 5虽说能够编译通过然而5不一定对应你所定义的任何枚举值这种隐式转换是C语言为了具备灵活性而留存的特性不过在实际项目当中应当尽可能予以规避。枚举与整数的转换陷阱存在这样一个状况隐式转换所引发的最为严重的问题便是类型安全出现失效的情况当你已然定义了一个枚举类型其原本的意图是对变量进行限定使其仅能够获取那几种特定的值然而由于存在能够随意赋予整数的情况导致这个原本设定的限制变得毫无作用就好像不存在一样在代码审查过程当中常常能够见到enum Color c 100; 这样的书写方式在后续使用c进行比较操作的时候只要在相应的判断过程中仅仅对RED、GREEN、BLUE进行了判断却遗漏掉了100这个并不合法的值那么便会继而产生那种很难进行排查的逻辑错误。GCC编译器于碰到枚举与整数混合使用情形之际一般会给出警告像将整数赋予枚举变量或者运用枚举变量跟整数作比较编译器就会给出类型不匹配的提示建议于编译之际加上-Wall -Wextra选项将警告当作错误来处置要是确实需要传入整数值应当运用显式类型转换写成(enum COLOR)0以使代码阅读者清晰明了这里是什么操作。// 创建枚举变量并赋值 enum COLOR color COLOR_RED; // 比较枚举变量 if (color COLOR_RED) { printf(COLOR_RED\n); } else { printf(COLOR_GREEN or COLOR_BLUE\n); }枚举在状态机中的应用用于嵌入式开发的状态机是常用模式而枚举特别适宜用以表示状态像一个能够售卖商品的自动售货机来说它存在IDLE、SELECTING、PAYING、DISPENSING、OUT_OF_STOCK这些状态当 employing枚举予以定义之后在 switch语句里面能够直接运用状态名如此代码逻辑清晰可见相较于运用0、1、2、3去代表状态使用枚举的版本几乎无需注释便可理解。用于异常处理的情况枚举也是有着很好的用途的。去定义一个错误码的枚举其中涵盖ERR_SUCCESS、ERR_TIMEOUT、ERR_INVALID_PARAM、ERR_MEMORY等等。函数进行返回的是这种枚举类型调用的一方借助判断返回的值便能够知晓发生了何种错误。相较于返回-1、-2这类数字而言枚举使得错误处理的代码具备自解释性在后续维护方面带来了极大的便利。枚举在实际项目中的规范实际项目里头对于枚举的运用存在着一些约定俗成的规范命名常常采用全大写加下划线的样式像是COLOR_RED这般能够一眼就瞧出是枚举常量枚举类型名一般加上后缀_T或者首字母大写例如color_t或者Color这些命名习惯虽说并非语法要求然而在大型项目当中能够极大地提升代码一致性。void func(enum COLOR color) { if (color COLOR_RED) { printf(COLOR_RED\n); } else { printf(COLOR_GREEN or COLOR_BLUE\n); } } func(COLOR_RED); // COLOR_RED // 隐式转换 func(0); // COLOR_RED // 显示转换 func((enum COLOR)0);存在一个容易被忽视掉的问题即枚举值的扩展性倘若枚举定义放在头文件里面后续要是需要增加新的值那么所有依赖这个头文件的源文件都得重新进行编译所以在设计公共的接口之时通常会预留一些值用以供未来扩展或者定义最大值宏就比如在枚举的最后添加一个MAX_XXX项它既能够被用来当作数组大小又方便后续去插入新的值。枚举与宏定义的选择众多的人会在何时运用枚举何时运用#define上陷入纠结。要是存在一组相关的常量像是星期、颜色、状态那么枚举便是更佳的选择。枚举将这些常量归拢到一个类型之下编译器能够给予更优的类型检查以及调试信息。在调试器当中你所看到的是MON而非0这对于定位问题有着极大的帮助。常量之间若不存在关联像是单个的缓冲区大小、超时时间这种情况选用#define会更为适宜。枚举同样不适宜用于定义位掩码之举虽说通过指定值能够达成然而枚举变量无法直接开展位运算得先转换为整数才行如此操作会显得颇为别扭。此外枚举的值在编译之际便已确定无法如同宏那般参与条件编译。要是枚举运用得恰到好处那代码读起来就好似小说一般。你所编写的每一处枚举皆是在给后续的维护人员讲述故事告知他们此处为何是这般的值此状态究竟代表着什么。那么随之而来的问题便是你于项目里最为常用枚举去管理什么呢是状态机、错误码还是配置选项呢欢迎在评论区域分享你的使用方式同时也千万别忘记点赞以便让更多的C语言开发者得以瞧见。