枚举是否是位域实现定义的类型?

我试图更好地理解C99标准,但现在我对使用枚举作为结构中的位域以及它们被视为int还是实现定义类型感到困惑。 在查看C99的最终草案时,我找到了6.7.2.1段。 4

位字段的类型应为_Boolsigned intunsigned int或其他实现定义类型的限定或非限定版本。

和6.7.2.2段。 4

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

所以我尝试使用这个简单的源代码

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的实现定义行为的变化。

正如您引用的标准部分所述,位字段必须是_Boolintunsigned int类型某些实现定义类型。

enum类型与某种整数类型兼容。 实验和gcc手册的显示表明,对于gcc,你的enum eunsigned int兼容。 但是该标准不允许位字段与unsigned int 兼容 。 它实际上必须是unsigned int类型(兼容类型不一定是同一类型)。 除了它也可以是其他一些实现定义的类型。

根据gcc 4.8.4的手册 :

  • _Boolsigned intunsigned int之外的允许位字段类型(C99 6.7.2.1)。

严格符合模式不允许其他类型。

根据gcc-5.2.0的手册:

  • _Boolsigned intunsigned int (C99和C11 6.7.2.1)之外的允许位字段类型。

即使在严格一致的模式下,也允许使用其他整数类型,例如long int和枚举类型。

所以你看到的是gcc行为的改变,即使在“严格符合模式”下也允许更多类型的位域。 这不是gcc对标准的解释的变化; 两种行为都是允许的。

使用enum作为位字段是不可移植的。 符合标准的C编译器可能支持也可能不支持它们。 (如果gcc能够为此发出警告,我本人会更喜欢它。)

它可能是安全的,但不要这样做。 你违反了隐含的合同设计。 有点。 你提到了这个构造,但没有提到你是如何使用它的。 可能有一种更清洁的方式。

如果你有:

 typedef enum { E0, E1, E2 } myenum_t; myenum_t val; 

现在,如果您有各种switch语句,例如:

 switch (val) { case E0: ... break; case E1: ... break; case E2: ... break; } 

它们将在编译时进行检查,以确保您的switch涵盖所有情况。 如果然后在枚举定义中添加E3 ,编译器会将switch语句标记为缺少E3 。 这很有用。

如果你开始咬住你的枚举值,你可能需要将你的switch改为:

 switch (val) { case E0: ... break; case E1: ... break; case E2: ... break; default: ... break; } 

现在,如果您将E3添加到枚举中,编译器将不会为丢失的case标记您的switch ,因为它假设default将处理它。 也许不是你想要的。

添加default值通常用于调试错误的枚举值。

但是,如果你有:

 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; 

并且,完成以下操作是完全正常的: bval.mask |= M2; 。 将位域切片和切块保留到int ,您可以在其中控制大小[种类]。 当使用标准的东西工作正常时,尝试应用半非便携式扩展没有任何优势。