在位字段 [dcl.enum] [class.bit] 中保存枚举类型

save enumeration type in bit-field [dcl.enum] [class.bit]

在下面的代码中,一个枚举类型的变量被保存到一个位域中。据我了解,可以在不丢失数据的情况下检索变量。然而,那是行不通的。

下面的输出是否符合标准?

#include<iostream>
using namespace std;
const int M=3, UL=(1<<M)-1;    // range 0 .. 7, fits into 3 bits
enum class ec { e_min=0, e_max=UL};
// in [decl.enum] (8): b_min==0 && b_max==7==2^M-1
struct bitFieldType {
    ec data : M;  // 3 bits
};
int main(){
  bitFieldType bf;
  for (int c=0; c<=UL; ++c){;
    ec enumIn { static_cast<ec>(c) }; // initialize enumeration type 
    bf.data = enumIn;                 // copy into bit-field
    ec enumOut{bf.data};              // retrieve enumeration type from bit-field
    cout<<static_cast<int>(enumIn) <<" "<< static_cast<int>(enumOut)
    << " " << (bf.data==enumIn) <<"\n";
  }
}

[dcl.enum] (8): "最小位域的大小足以容纳 如果 b min 为零,则枚举类型的所有值都是 max(M, 1) ...” [class.bit] (4) " 枚举器的值存储在相同的位字段中 枚举类型和位域中的位数足够大 保存该枚举类型(10.2)的所有值,原始 枚举值和位域的值 应比较相等。

如果是这样,为什么输出看起来像这样?

clang++ -Wall -fsanitize=undefined -pedantic -std=c++17 bitf.cpp && ./a.out
0 0 1
1 1 1
2 2 1
3 3 1
4 -4 0
5 -3 0
6 -2 0
7 -1 0
clang++ --version
clang version 9.0.0 (trunk 351995)
Target: x86_64-unknown-linux-gnu

编辑:添加了一个 static_cast<>() 以便代码编译时 'enum class' 替换为普通的 'enum'.

使用纯 'enum' 而不是 'enum class',输出符合预期。此外,在位字段中增加一位,输出符合预期。

我读得太快了。从枚举 class 开始,您遇到了更大的问题。奇怪的是,如果我从警告消失的枚举声明中删除 "class";

Is it safe to use an enum in a bit field?

g++     foo.cpp   -o foo
foo.cpp:7:15: warning: ‘bitFieldType::data’ is too small to hold all values of ‘enum class ec’
     ec data : M;  // 3 bits
               ^
foo.cpp: In function ‘int main()’:
foo.cpp:12:19: error: cannot convert ‘int’ to ‘ec’ in initialization
     ec enumIn { c };           // initialize enumeration type
                   ^
<builtin>: recipe for target 'foo' failed
make: *** [foo] Error 1

g++ --version
g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

结果是 ,它解释了符号扩展。只需指定类型就可以了,尽管编译时仍会出现警告。

#include<iostream>
using namespace std;
const int M=3, UL=(1<<M)-1;    // range 0 .. 7, fits into 3 bits
enum class ec : unsigned int { e_min=0, e_max=UL};
// in [decl.enum] (8): b_min==0 && b_max==7==2^M-1
struct bitFieldType {
    ec data : M;  // 3 bits
};
int main(){
  bitFieldType bf;
  for (int c=0; c<=UL; ++c){;
    ec enumIn { (ec)(c) };           // initialize enumeration type
    bf.data = enumIn;          // copy into bit-field
    ec enumOut{bf.data};       // retrieve enumeration type from bit-field
    cout<<static_cast<int>(enumIn) <<" "<< static_cast<int>(enumOut)
    << " " << (bf.data==enumIn) <<"\n";
  }
}
/*
0 0 1
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 1
7 7 1
*/

你的ec,在范围内,有一个fixed underlying type of int, so its values are all those of int and your bit-field is not wide enough to guarantee anything. In practice, it’s probably being interpreted as a signed bit-field which needs to be of width 4 to store the values 4–7 (even though the rule about signedness没有明确定义枚举类型的符号是它的底层类型)。