C语言中枚举类型溢出



如果我有一个enum类型,如:

enum week{ sunday=0, monday, tuesday, wednesday, thursday, friday, saturday};

和我有:

enum week day;
day = saturday;
day++;

day的值是多少?

枚举类型本质上是命名整型值。该枚举类型与可以表示所有命名值的底层整型相关联。底层的整型需要能够表示所有唯一的命名值,但它的实际类型是实现定义的。

在此例中,saturday的数值为6。增加它将得到7的数值。实际上,这不大可能溢出底层的整型(intcharunsigned char或编译器选择的任何类型),因此使用%d格式打印值将打印7

但是,没有enum week类型的枚举(命名)值为7

如果增加枚举值会溢出底层整型(这里不是这种情况),则结果是未定义的。这是因为底层的整型可以是有符号的也可以是无符号的,溢出有符号的整型会产生未定义的行为。

从理论上讲,编译器可能会使用enum week的底层类型,该类型只能表示06的值,在这种情况下,增加saturday会产生未定义的行为。在实践中,我敢说,还没有任何C编译器不选择底层类型作为标准整型(char, int, unsigned char, unsigned等)之一。所有这些类型都可以表示7的数值

给定:

enum week {
    sunday=0, monday, tuesday, wednesday, thursday, friday, saturday
};
enum week day = saturday;
day ++;

day的值为7

引用2011 ISO C标准,6.7.2.2第1段:

每个枚举类型必须兼容 char ,一个有符号的整数类型,或无符号整数类型。类型的选择是实现定义的,但应能够表示枚举中所有成员的值。

_Bool是一个无符号整数类型,但是它不满足这个特定枚举类型的要求。

由于CHAR_BIT的值要求至少为8,并且charunsigned charsigned char类型要求没有填充位,因此每种字符类型的范围必须至少覆盖0127。更宽的整数类型(short, int等)的取值范围至少与signed charunsigned char一样宽。因此,与enum week兼容的实现定义类型的下界必须不大于0,上界必须不小于127

(WARNING: Language-lawyering following .)可能存在一个漏洞,允许扩展的整数类型具有比_Bool更宽的范围,但比char更窄的范围。例如,我认为是一个扩展的整数类型,其大小为8位,但只有3个值位是合法的。但是由于整数类型需要使用二进制表示,具有3个值位的无符号类型将能够表示从0到7的值,而具有2个值位的无符号类型将无法表示saturday的值。因为enum week可以保存值6,所以它也必须能够保存值7。在一个不寻常的实现中,它可能不能表示值8,但是您不太可能遇到这样的实现。

基本上,给定整数类型使用纯二进制表示的要求,任何可以表示6的类型也可以表示7,尽管它并不能自动推导出它也可以表示8

我只能找到C89规范的草案,我不是C语言专家,所以我可能会误解它。但是它的3.5.2.2节说

枚举器列表中的标识符被声明为具有的常量在允许的地方输入int和。[…]每个被列举的类型必须与整型兼容。

我认为这意味着day++在这里总是会产生7(比saturday所代表的值多一个)。

最新更新