在字段中使用枚举是否安全?

时间:2012-08-16 08:23:47

标签: c++ c enums bit-fields

说,我有以下结构:

typedef struct my_struct{
    unsigned long       a;
    unsigned long       b;
    char*               c;
    unsigned int        d1  :1;
    unsigned int        d2  :4;
    unsigned int        d3  :4;
    unsigned int        d4  :23;
} my_type, *p_type;

字段d3目前由#define定义,从0x000x0D

实际上,d3是一个枚举。所以很有可能继续取代

    unsigned int        d3  :4;

通过

    my_enum             d3  :4;

这是安全/允许的吗?

代码必须使用各种

进行编译
  • 编译器(GCC,Visual Studio,嵌入式东西)
  • 平台(Win32,Linux,嵌入式内容)
  • 配置(编译为C,编译为C ++)

显然,我可以保留d3的定义,并在我的代码中使用枚举,将其分配给d3等等,但这不适用于C ++。

4 个答案:

答案 0 :(得分:22)

所有支持标准的C ++编译器都允许这样做。

C ++ 03标准9.6 / 3

位域应具有整数或枚举类型(3.9.1)。它是 实现 - 定义是否为明文(既未明确签名也未签名)char,short,int或 长位字段有符号或无符号。

C ++ 03标准9.6 / 4

如果enu-的价值 merator存储在相同枚举类型的位字段中,并且位字段中的位数很大 足以保存该枚举类型的所有值,原始枚举器值和位字段的值应相等。

例如

enum BOOL { f=0, t=1 };

struct A {
    BOOL b:1;
};

void f() {
    A a;
    a.b = t;
    a.b == t // shall yield true
}

但你不能认为枚举有未签名的底层类型。

C ++ 03标准7.2 / 5

枚举的基础类型是可以表示所有枚举器值的整数类型 在枚举中定义。它是实现定义的,其中整数类型用作底层类型 对于枚举,除了基础类型不应大于int,除非enu-的值 merator无法放入int或unsigned int

答案 1 :(得分:13)

C和C ++的答案会有所不同,这是C语言的答案。

在C中,位域仅限于signed intunsigned int_Boolint,在此上下文中可以是前两个中的任何一个。编译器实现者可以根据自己的喜好添加该列表,但需要记录它们支持的类型。

所以要回答你的问题,如果你想确保你的代码可以移植到所有的C编译器,不,使用enum类型不是一种选择。

现行标准的相应段落为:

  

位字段应具有合格或不合格的类型   _Bool的版本,已签名        int,unsigned int或其他一些实现定义的类型。它是         实现 - 定义是否允许原子类型。

答案 2 :(得分:6)

没有

在编译器之间实现位字段的显着不同。如果你定义一个具有两个值的位字段,零和一个,并尝试使用枚举类型的位字段,那么你可能会遇到这些问题:

位字段将使用gcc和clang无符号,但使用VC ++进行签名。这意味着为了存储零和一,你需要一个两位的位字段(一位有符号位字段只能存储零和负一位)。

然后你必须担心包装。如果大小匹配,VC ++只会将相邻的位字段打包到同一个后备存储中。我不确定gcc和clang的规则是什么,但对于VC ++,位字段的默认后备存储是int。因此,一系列比特字段,例如,bool和enum的混合,将用VC ++打包得非常糟糕。

您可以尝试使用C ++ 11类型的枚举来解决此问题:

enum Foo:unsigned char {one,two};

但是如果你在一位位字段中使用它,gcc会抱怨:

警告:'bitfieldTest :: g'太小,无法容纳'enum Foo'的所有值[默认启用]

似乎没有胜利。

答案 3 :(得分:0)

在C中,这是一种未定义的行为,因为位字段只能有signed intintunsigned int类型(或_Bool与C99)。

6.5.2.1

  

位字段应具有合格或不合格的类型   int,unsigned int或signed int之一的版本。是否   (可能合格的)“plain”int的高位位置   位字段被视为符号位是实现定义的。一个   位字段被解释为由...组成的整数类型   指定的位数。

否则,一些编译器今天接受它作为扩展(参见标准中扩展的实现定义行为)。