在位字段 [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没有明确定义枚举类型的符号是它的底层类型)。
在下面的代码中,一个枚举类型的变量被保存到一个位域中。据我了解,可以在不丢失数据的情况下检索变量。然而,那是行不通的。
下面的输出是否符合标准?
#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没有明确定义枚举类型的符号是它的底层类型)。