C 是否将枚举定义为位字段实现类型?
我试图更好地理解C99标准,但现在我对在结构中使用枚举作为位字段以及它们是否被视为int或实现定义的类型感到困惑。在查看C99的最终草案时,我发现了6.7.2.1段。四, 位字段的类型应为合格或不合格版本的\u Bool,有符号整数,无符号整数,或其他实现定义的类型 以及第6.7.2.2段。四, 每个枚举类型应与字符、有符号整数类型或无符号整数类型兼容。类型的选择由实现定义,但应能够表示枚举的所有成员的值 所以我尝试了这个简单的源代码C 是否将枚举定义为位字段实现类型?,c,language-lawyer,c99,C,Language Lawyer,C99,我试图更好地理解C99标准,但现在我对在结构中使用枚举作为位字段以及它们是否被视为int或实现定义的类型感到困惑。在查看C99的最终草案时,我发现了6.7.2.1段。四, 位字段的类型应为合格或不合格版本的\u Bool,有符号整数,无符号整数,或其他实现定义的类型 以及第6.7.2.2段。四, 每个枚举类型应与字符、有符号整数类型或无符号整数类型兼容。类型的选择由实现定义,但应能够表示枚举的所有成员的值 所以我尝试了这个简单的源代码 enum e { E0, E1 }; struct
enum e {
E0, E1
};
struct s {
enum e bitfield : 4;
};
我可以使用gcc-5.0和clang-3.5,使用-std=c99-Wall-Wextra-pedantic
编译此文件,而不会出现警告,但我使用gcc-4.8得到以下警告
warning: type of bit-field 'bitfield' is a GCC extension
这里开始混乱。作为位字段的枚举是否被视为int类型或实现定义的类型?这是GCC-4.8中的错误,还是他们更改了对标准的解释?与其他C99编译器一起使用是否安全
是否将枚举定义为位字段实现类型
对
您看到的是gcc的实现定义行为的变化
正如您引用的标准部分所述,位字段的类型必须为\u Bool
、int
、unsigned int
,或某种实现定义的类型
enum
类型与某些整数类型兼容。实验和gcc手册表明,对于gcc,enum e
与unsigned int
兼容。但该标准不允许位字段的类型与无符号int
兼容。它实际上必须是类型unsigned int
(兼容类型不一定是同一类型)。除此之外,它还可以是其他实现定义的类型
根据报告:
- 除了
、\u Bool
和有符号整数
(C99 6.7.2.1)之外,允许的位字段类型无符号整数
- 除了
、\u Bool
和有符号整数
(C99和C11 6.7.2.1)之外,允许的位字段类型无符号整数
long int
,以及枚举类型
因此,您看到的是gcc行为的变化,即使在“严格一致模式”下,也允许更多类型的位字段。这不是gcc对本标准解释的变更;这两种行为都是允许的
使用
enum
s作为位字段是不可移植的。一致性C编译器可能支持也可能不支持它们。(我个人更希望gcc能够获得警告。)这可能是安全的,但不要这样做。你违反了合同中的默示设计。某种程度上。您提到了构造,但没有提到您真正想要如何使用它。也许有更干净的方法
如果您有:
typedef enum {
E0, E1, E2
} myenum_t;
myenum_t val;
现在,如果您有各种switch语句,例如:
switch (val) {
case E0:
...
break;
case E1:
...
break;
case E2:
...
break;
}
它们将在编译时进行检查,以确保您的开关涵盖所有情况。如果随后将E3
添加到枚举定义中,编译器会将开关
语句标记为缺少E3
。这是有用的
如果开始对枚举值进行位欺骗,则可能必须将开关更改为:
switch (val) {
case E0:
...
break;
case E1:
...
break;
case E2:
...
break;
default:
...
break;
}
现在,如果将E3
添加到枚举中,编译器不会为缺少的大小写标记开关
,因为它假定默认值
将处理它。也许不是你想要的
添加默认值通常是为了调试错误的枚举值
但是,如果您有:
typedef struct {
unsigned int mask:8;
unsigned int enval:8;
unsigned int ident:8;
unsigned int other:8;
} mybit_t;
mybit_t bval;
使用以下命令:
switch ((myenum_t) bval.enval) {
...
}
可能更干净一点,可能更接近你真正希望实现的目标
“隐含契约”是指[在此上下文中]枚举是一组整数。请注意,您还可以拥有:
typedef enum {
M0 = 1 << E0, M1 = 1 << E1, M2 = 1 << E2
} mymask_t;
typedef枚举{
M0=1@Rhymoid的可能重复项我不确定这是否真的是重复项。AFAIK是无符号字符,是无符号int的子类型,而enum可以等效于int。也可能是我误解了“与[…]整型兼容”在6.7.2.2第4段中,第一个引号表示其实现定义了允许使用哪些其他类型作为位字段