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

eck*_*kes 26 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;
Run Code Online (Sandbox Code Playgroud)

该字段d3目前由直到#define达到的s 定义.0x000x0D

实际上,d3是一个枚举.所以很有可能继续前进并取而代之

    unsigned int        d3  :4;
Run Code Online (Sandbox Code Playgroud)

通过

    my_enum             d3  :4;
Run Code Online (Sandbox Code Playgroud)

这是安全/允许的吗?

代码必须用各种编译

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

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

For*_*veR 22

它允许在所有支持标准的C++编译器中使用.

C++ 03标准9.6/3

位域应具有整数或枚举类型(3.9.1).它是实现定义的是明文(既没有显式签名也没有未签名)char,short,int或long位字段是有符号还是无符号.

C++ 03标准9.6/4

如果将枚举器的值存储到相同枚举类型的位字段中,并且位字段中的位数足以容纳该枚举类型的所有值,则原始枚举器值和值比特字段应比较相等.

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

struct A {
    BOOL b:1;
};

void f() {
    A a;
    a.b = t;
    a.b == t // shall yield true
}
Run Code Online (Sandbox Code Playgroud)

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

C++ 03标准7.2/5

枚举的基础类型是一个整数类型,可以表示枚举中定义的所有枚举器值.它是实现定义的,其中整数类型用作枚举的基础类型,除了基础类型不应大于int,除非枚举器的值不能适合int或unsigned int


Jen*_*edt 13

对于C和C++,答案会有所不同,这对于C.

在C位域被限制为signed int,unsigned int,_Boolint其在这种情况下可以是任何前两个.编译器实现者可以根据自己的喜好添加到该列表,但需要记录它们支持的类型.

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

现行标准的相应段落如下:

位字段的类型应为_Bool,signed int,unsigned int或其他实现定义类型的限定或非限定版本.它是实现定义的,是否允许原子类型.

  • 我通常使用`#ifdef __GNUC__ #define ENUMBF(type) __extension__ type #else #define ENUMBF(type) unsigned #endif`。然后将 `ENUMBF(myenum) field:x;` 放入我的结构中。代码不太好,但您不会错过重要的 gcc 警告,例如当您的位域太小时,因为同事向枚举添加了更多案例... (2认同)

Bru*_*son 7

没有.

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

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

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

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

enum Foo:unsigned char {one,two};

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

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

似乎没有胜利.

  • 现在这个已经过时了;[gcc 修复了执行此操作的错误](https://godbolt.org/z/xz7fKzchs)。您现在可以将二值枚举放入一位位字段中。 (2认同)