在C语言里,有这样一种类型,它看起来好像挺简单的,然而却常常被人给忽视掉,它就是枚举类型,这可是个挺实用的工具呢。好多刚开始学的人会觉得它好像没有也行,可是在真正去做项目开发的时候,要是能合理地去运用枚举,那就能够让代码的那种可以被读懂的程度以及能够被维护的程度得到极大的提高,还能把那些特别让人头疼的"魔术数字"给减少掉。
枚举类型到底是什么
一种把整数值赋予有含义名称的数据类型,其本质是枚举类型,在C语言里,它是借助enum关键字来进行定义的,比如说你编写一个处理星期的程序,要是直接采用数字1到7,三天之后再回看代码的话,或许就会忘掉数字1究竟是代表周一还是周日,然而使用枚举进行定义之后呢,Monday、Tuesday这类名称会直接向你表明其含义,并且编译器在底层会为它们分配整数值。
要说声明一个枚举变量之时,事实上是在告知编译器,此变量的取值仅仅能够是我所列出的这几个选项其中之一,这样一种限制看着是约束情形,然而实际上却是一种保护举措,它避免了代码里出现不在预期范围之内的无效值,使得程序运行更为稳定靠谱。
c
enum Fruits(Watermelon,Mango,Grape,Orange,Apple);
枚举常量的值分配规则
于枚举定义里头,要是未曾进行显式指定值的操作,头一个枚举常量会默认自0起始,后续的那些会逐个依次递增,即像enum Weekday {Mon, Tue, Wed}这样,Mon为0,Tue为为1,Wed为2,此规则简便径直,于多数状况下都是适用的。
然而枚举的切实灵活所在乃是能够手动进行赋值,你能够针对某个常量赋予特定的整数值,后续未被赋值的常量会基于此持续递增,比如说enum Fruits,其包含Watermelon这一赋值为1的常量,Mango常量,Grape常量,Orange常量以及Apple常量,在这个枚举中,Watermelon的值为1 ,Mango会自动转变为2 ,Grape的值是3 ,依此类推,这样的特性在面临需要与外部系统实现对接或者维持特定数值映射的情形时极具用处。
枚举变量的声明与使用
当完成枚举类型的定义之后,便能够运用它去声明变量了。声明的方式与int、char等基础类型是一样这般:enum Weekday today。此变量today仅仅能够被赋值成为Weekday枚举之中所定义的常量,就像today = Mon。要是你尝试给它赋予一个并不在枚举列表里的整数值,编译器大部分情况下会给出警告。
c
enum Fruits(Watermelon=1,Mango,Grape,Orange,Apple);
现实当中的实际代码里,枚举类型的变量常常会出现在switch语句之中。这是由于枚举所拥有的值是一组呈现出来离散状态的选项,运用switch语句去处理这些选项的时候,逻辑显得清晰明了,代码的整体结构那是一目了然。每一个case分支都相应地直接对应着一个枚举常量,而且编译器能够帮助你去检查是不是遗漏了某些分支,这样的一种静态检查方式对于减少程序当中存在的bug是大有益处的。
枚举与#define的区别
好些刚开始学习的人会问,枚举跟用#define去定义一组常量存在着什么样的区别呢,从表面上来看,这两者都能够达成相似的效果,然而枚举具备几个较为明显的优势,枚举创建出了一种全新的类型,编译器能够针对枚举变量开展类型检查,而#define仅仅是进行简单的文本替换,缺少类型方面的约束。
调试之际,枚举更具实用价值。于多数调试器而言,你能够直接目睹枚举常量之名,而非单一数字呈现。举例来讲,若变量值为Mon,调试器所展示的将是"Mon",而非"0"。并且,枚举常量依循作用域规则,不会如#define那般对全局命名空间造成污染。随着项目规模不断拓展,这些特性会使得代码管理显著轻松许多。
c
enum Color { RED, GREEN, BLUE };
enum Color myColor = RED; // 正确
enum Color myColor1 = 2; // 错误
枚举在实际项目中的应用场景
可用于列举的最具代表性的应用情形是状态机,像是网络连接状况能够借助枚举予以界定,即DISCONNECTED、CONNECTING、CONNECTED、FAILED ,程序依据当下状态施行各异的逻辑,状态转换之际仅能选取这几个数值,防止了运用数字进行表示时有可能出现的非法状态组合。
又一常见情形为配置选项,像程序存在几种运行模式,即DEBUG、TEST、PRODUCTION,借助枚举去界定这些模式,于代码里径直运用有实质意义的名称,相较于记性0、1、2要直观许多,再者当你有必要增添新模式之际,仅需于枚举内添入一项,编译器会帮你找寻出所有需处理新模式的地方。
c
#include
int main(){
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
scanf("%d", &day); // C语言允许用 scanf() 为枚举变量读取一个整数
switch(day){
case Mon: puts("Monday"); break;
case Tues: puts("Tuesday"); break;
case Wed: puts("Wednesday"); break;
case Thurs: puts("Thursday"); break;
case Fri: puts("Friday"); break;
case Sat: puts("Saturday"); break;
case Sun: puts("Sunday"); break;
default: puts("Error!");
}
return 0;
}
使用枚举时需要注意的细节
同一作用域里的枚举常量得是唯一的,你没办法在同一个作用域当中去定义两个有着相同名称常量的枚举,就好比无法在两个不一样的枚举里面都去定义RED一样,这种限制有时候会造成困扰,不过C11标准引入了enum的前置声明以及更具灵活性的作用域规则,这就在一定程度上把这个问题给缓解。
通常而言,枚举的底层类型是int,这表明枚举变量所占据的内存大小与int一样。要是你有更小内存占用的需求,可考虑借助编译器扩展或者C23标准里新增的指定枚举底层类型的那种特性。此外,枚举常量能够是负数,这在用于表示错误码或者特殊状态之际是颇为有用的,不过要留意维持一致性,防止致使代码变得难以让人理解。
于实际进行编码期间,你曾碰到过因过度使用数字常量致使代码维护起来颇具难度的情形吗?欢迎于评论区域去分享你的相关经历,点赞以便让更多人能够瞧见枚举类型的正确运用方式。