今天说说C语言中的枚举。
参考:Enumeration (or enum) in C
1 定义
定义一个枚举类型很容易:
enum aa { a1, a2, a3 };
这里
- enum是关键字
- aa是枚举变量,也就是我们自定义类型
- a1,a2,a3是枚举成员
然后怎么使用呢?
首先,它就像结构体struct
和联合体union
那样,是一个自定义的数据类型,用它定义变量,也是一样的:
enum aa abc; // 定义变量
enum aa *en_p; // 定义指针
是的,它跟基本数据类型以及结构体等特殊数据类型一样,都可以定义变量和定义指针。
所以,和int
一样,如果仅仅定义,而没有赋值和使用,编译后它就没了,变量定义本身不占地方,赋值了才占地方。
另外,和struct
一样,它只是一个结构,这个结构是C语言层级的声明,编译后不存在这个结构的,汇编层级没有的。
所以,下面我们先说说,变量的赋值
2 变量的赋值
枚举类型的赋值其实是比较复杂的,先说最常用的。
2.1 默认值
enum aa { a1, a2, a3 };
对于上述枚举类型,它的a1 a2 a3
, 在默认情况下,会被赋值为
a1 = 0;
a2 = 1;
a3 = 2;
2.2 赋初值
enum aa { a1 = 1, a2 = 3, a3 = 5 };
可以对其任意赋初值,这样,三个枚举成员的值就对应了你指定的值了。
我们看看多种情况:
情况1:全都赋初值
enum aa { a1 = 1, a2 = 3, a3 = 5 };
情况2:有重复的初值
这种情况的完全可以的。
enum aa { a1 = 1, a2 = 1, a3 = 5 };
情况3:部分赋初值,部分不赋值
enum aa { a1 = 1, a2, a3 };
对于此时,a2 = 2 a3 = 3
,也就是说,后面没有赋值的,是默认根据前面赋值的累加的。
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
那这种情况呢?
- 根据a1累加:
a2 = 2 a3 = 3 a4 = 4
- 根据a4累加:
a5 = 11 a6 = 12
赋值范围
与int类型赋值范围一样!赋值-1
什么的也可以,与int类型的范围一样的。
2.3 变量赋值
其实就是定义一个变量,然后给它赋值,这里不一样的是,枚举成员本身,就代表值。
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
enum aa abc = a2;
这个时候,abc = 2
,a2就代表数值2.
从其他角度理解,enum aa abc = a2;
的含义就是
int a2 = 2;
int abc = a2;
就是这么个意思。
2.4 指针赋值
enum aa abc = a2;
enum aa *enu_p = &abc;
printf("%d\n", *enu_p);
没啥好说的,跟基本数据类型指针待遇一样的。
3 谈谈枚举成员
3.1 作用范围
首先,结构体本身
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
它的作用范围,跟struct
一样,跟int
也一样,在{ }
里面就是局部变量,在最外面就是全局变量,对于aa
这个自定义类型标识符,也是一样的,不多说了。
比较需要注意的是,枚举成员也是标识符。
3.2 枚举成员也是标识符
我们上面的例子,a1,a2,a6
这些,在其作用域内,也是标识符,也就是相当于你定义了一个int a1;
一样,在作用域内不能重复定义了!并且,这个标识符本身代表了一个int值。
int main(){enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };int a1; // error!重定义了!上面定义过a1了!enum bb {a2,a4}; // error!
}
4 enum与int
enum中的枚举成员,都是int类型的变量,也代表int类型的值,值的范围也是int的范围。
5 enum与#define
5.1 共同点
下面两段代码基本来说是等价的:
#define Working 0
#define Failed 1
#define Freezed 2
enum state {Working, Failed, Freezed};
5.2 enum的优势
#define是全局的,而enum则是与基本数据类型一样,范围非常灵活。
5.3 #define的优势
enum只能定义int类型值,define什么都可以等价,任何值,以及函数,都可以。
6 enum的大小(size)
6.1 变量的大小
注意:讨论enum结构本身大小没必要,因为其变量,就是这个结构的实例化,这一点和struct一样的!
enum aa { a1 = 10, a2, a3 };
enum aa abc = a2;
printf("size = %d\n", sizeof(enum aa)); // 4
printf("size = %d\n", sizeof(abc)); // 4
试一下就知到了,都是4字节
。这俩肯定相等,一个是模板,一个是实例。
为什么是4呢?
因为enum这里面的值,其实就是int
类型的,那不就是4吗!然后这个枚举变量,值只能有一个吧,那就占一个4字节空间足够了。
像struct那是可以有多个值,所以每个变量都占空间,这个就没必要,一堆里面选一个就可以了。
另外就是,不要试图获取枚举成员的地址,因为它有没有用上场都不一定呢,它只是C语言层级的一个值而已,不一定被分配。
好吧,没人这么闲的没事干。
7 奇奇怪怪
enum aa abc = 100;
printf("***%d\n", abc); // 100
这种情况下,就真的当int用了,其实也没啥,反正编译器允许,不过一般没人这么干。
8 最后,说说真正常用的地方
说实话,说了这么多,基本都很少用得到!常用的地方也就固定套路,内些野路子你看看就好。
就比如你定义个月份什么,星期什么的。
#include<stdio.h>enum year{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};int main()
{int i;for (i=Jan; i<=Dec; i++) printf("%d ", i);return 0;
}
另外还有就是,编译原理中的,词法分析器的单词表,需要把编号和名称对应起来,enum是天然适合的结构,使用struct嵌套enum和其他,就很完美很方便。