嵌入式开发-枚举详解 朱有鹏 1.枚举 m 1.1、枚举是用来干嘛的? #include <stdio.h> // 这个枚举用来表示函数返回值,ERROR表示错,RIGHT表示对 enum return_value { ERROR, // 枚举值常量是全局的,直接自己就可以用。 RIGHT, }; enum return_value func1(void); int main(void) { enum return_value r = func1(); if (r == RIGHT) // 不是r.RIGHT,也不是return_value.RIGHT { printf("函数执行正确\n"); } else { printf("函数执行错误\n"); } printf("ERROR = %d.\n", ERROR); // ERROR = 0 printf("RIGHT = %d.\n", RIGHT); // RIGHT = 1证明枚举 //中的枚举值是常量 return 0; } enum return_value func1(void) { enum return_value r1; r1 = ERROR; return r1; } 枚举在C语言中其实是一些符号常量集。直白点说:枚举定义了一些符号,这些符号的本质就是int类型的常量,每个符号和一个常量绑定。这个符号就表示一个自定义的一个识别码,编译器对枚举的认知就是符号常量所绑定的那个int类型的数字。 枚举中的枚举值都是常量,怎么验证? 枚举符号常来那个来说,数字不重要,符号才重要。符号对应的数字只要彼此不相同即可,没有别的要求。所以一般情况下我们都不会明确指定这个符号所对应的数字,而是让编译器自动分配。编译器自动分配的原则是,从0开始依次增加,如果用户自己定义了一个值,则从定义的那个值开始往后依次增加。 1.2、C语言为何需要枚举 C语言没有枚举是可以的。使用枚举其实就是对1、0这些数字进行符号化编码,这样的好处就是编程时可以不用看数字而直接看符号。符号的意义是显然的,一眼可以看出。而数字所代表的含义除非看文档或者注释。 宏定义的目的和意义是,不用数字而用符号,从这里可以看出,宏定义和枚举有内在联系。宏定义和枚举经常用来解决类似的问题,他们俩基本可以互换,但是有一些细微差别。 1.3、宏定义和枚举的区别 枚举是将多个有关联的符号封装在一个枚举中,而宏定义是完全散的。什么情况下用枚举?当我们要定义的常量是一个有限集合时(譬如一星期有7天,譬如一个月有31天,譬如一年有12个月····),最适合用枚举。(其实宏定义也行,但是枚举更好),不能用枚举的情况下(定义的常量符号之间无关联,或者无限的)用宏定义。 宏定义最先出现,用来解决符号常量的问题,后来人们发现有时候定义的符号常量彼此之间有关联(多选一的关系),用宏定义来做虽然可以但是不贴切,于是乎发明了枚举来解决这种情况。 1.4、枚举的各种不同的定义形式 (1)定义方法1:定义类型和定义变量分离开 enum week { SUN, // SUN = 0 MON, // MON = 1; TUE, WEN, THU, FRI, SAT, }; enum week today; (2)定义方法2:定义类型的同时定义变量 enum week { SUN, // SUN = 0 MON, // MON = 1; TUE, WEN, THU, FRI, SAT, }today,yesterday; (3)定义方法3,定义类型的同时定义变量 enum { SUN, // SUN = 0 MON, // MON = 1; TUE, WEN, THU, FRI, SAT, }today,yesterday; (4)定义方法4:用typedef定义枚举类型别名,并在后面使用别名进行变量定义 typedef enum week { SUN, // SUN = 0 MON, // MON = 1; TUE, WEN, THU, FRI, SAT, }week; (5)定义方法5:用typedef定义枚举类型别名 typedef enum { SUN, // SUN = 0 MON, // MON = 1; TUE, WEN, THU, FRI, SAT, }week; 注意: (1)不能有重名的枚举类型 即在一个文件中不能有两个或两个以上的enum被typedef成相同的别名。这很好理解,因为将两种不同类型重命名为相同的别名,这会让gcc在还原别名时遇到困惑。比如你定义了typedef int INT; typedef char INT; 那么INT代表的是int还是char呢? (2)不能有重名的枚举成员 两个struct类型内的成员名称是可以重名的,而两个enum类型中的成员却不可以重名。因为struct类型成员的访问方式为 变量名.成员,而enum成员的访问方式为 成员名,因此若两个enum类型中有重名的成员,那代码中访问这个成员时到底指的是哪个enum中的成员呢? 但是两个#define宏定义是可以重名的,该宏名真正的值取决于最后一次定义的值。编译器会给出警告但不会error。
|