枚举
一个枚举是一个类型,它可以保存一组由用户刻画的值。一旦定义之后,枚举的使用就很像是一个整数类型。
命名的整数常量可以定义为枚举的成员。例如
enum { ASM, AUTO, BREAK };
这就定义了三个被称为枚举符的整数常量,并给他们赋了值。按默认方式,枚举符所赋的值从0开始递增,所以ASM == 0,AUTO == 1,BREAK == 2。枚举也可以命名,例如,
enum keyword { ASM, AUTO, BREAK };
每个枚举都是一个独立的类型,枚举符的类型就是它所在的那个枚举。例如,AUTO的类型就是keyword。
将一个变量声明为keyword而不是一个普通的int,能够给用户和编译器一些有关该变量拟议中的用途的提示。例如,
void f(keyword key)
{
switch(key)
{
case ASM:
// 做某些事情
break;
case BREAK:
// 做某些事情
break;
}
}
编译器由可能提出一个警告,因为在三个keyword值中只有两个被处理了。
枚举符也可以用整型(4.1.1节)的constant-expression(常量表达式)(C.5节)进行初始化。如果某个枚举中所有枚举符的值均非负,该枚举的表示范围就是[0:2的k次方 - 1],其中的2的k次方是能使所有枚举符位于此范围内的最小的2的幂;如果存在负的枚举符值,该枚举的取值范围就是[-2的k次方 : 2的k次方-1]。这样就定义了一个最小的位段,其中能保存所有枚举符值的常规2补码表示,例如,
enum e1 { dark, light }; // 范围0:1
enum e2 { a = 3, b = 9 }; // 范围0:15
enum e3 { min = -10, max = 1000000 }; // 范围 -1048576:1048575
一个整型值可以显式地转换到一个枚举值。除非这种转换的结果位于该枚举的范围之内,否则就是无定义的。例如,
enum flag { x = 1, y = 2, z = 4, e = 8 }; // 范围0:15
flag f1 = 5; // 类型错❌:5不是flag类型
flag f2 = flag(5); // 可以:flag(5)是flag类型且在flag的范围之内
flag f3 = flag(z|e); // 可以:flag(12)是flag类型且在flag的范围之内
flag f4 = flag(99); // 无定义:99不在flag的范围之内
最后一个赋值说明了为什么不允许隐式地从整数转换到枚举:大部分整数值在特定的枚举里都没有对应的表示。
有关枚举的值范围的概念与Pascal一族语言中的枚举概念不同。无论如何,有关按位操作的各种例子在C和C++里已经有很长的历史了,其中都要求对超出枚举符集合的值有良好的定义。
一个枚举的sizeof就是某个能够容纳其范围的整型的sizeof,而且不会大于sizeof(int),除非有某个枚举符的值不能用int也不能用unsigned int表示。举例来说,在sizeof(int) == 4的机器上,sizeof(e1)可以是1,也可能是4,但绝对不会是8。
按照默认方式,枚举可以转换到整数去参加算术运算(6.2节)。一个枚举是一个用户定义类型,所以用户可以为枚举定义它自身的操作,例如定义++或<<(11.2.3节)。
🔚