警告:
src/BoardRep.h:49:12: warning: ‘BoardRep::BoardRep::Row::<anonymous struct>::a’
is too small to hold all values of ‘enum class BoardRep::Piece’
[enabled by default]
Piece a:2;
^
枚举:
enum class Piece: unsigned char {
EMPTY,
WHITE,
BLACK
};
用途:
union Row {
struct {
Piece a:2;
Piece b:2;
Piece c:2;
Piece d:2;
Piece e:2;
Piece f:2;
Piece g:2;
Piece h:2;
};
unsigned short raw;
};
对于enum
,我同意GCC,它可能必须截断,但这是因为enum
与整数和预处理器定义并不是真正分开的。然而enum class
要强得多。如果它不够强,无法假设所有作为整数的Piece
值都在0和2之间(包括0和2(,则该警告是有意义的。否则,GCC是不必要的挑剔,可能值得邮寄列表说"看,这是一个愚蠢的警告">
如果任何人都看不到这一点
你可以在2位数据中存储4个不同的值,我只需要3个不同的数值,所以任何长度为4或更小的枚举都应该很好地适应给定的2位(我的枚举确实从无符号类型"派生"(更好的术语?((。如果我有5个或更多,那么我会得到警告。
gcc
发出的警告是准确的,不需要向邮件列表中发送邮件,要求他们降低警告出现的可能性。
该标准规定,底层类型为unsigned char
的枚举不能用长度为2
的位字段表示;即使不存在具有这样的值的枚举。
标准
枚举的基础值是有效的,即使没有对应于该值的枚举键,标准只规定要存储在枚举中的合法值必须适合基础类型;它没有声明这样的值必须存在于枚举键中。
7.2枚举声明
[dcl.enum]
7 可以定义一个枚举,该枚举的值未由其任何枚举器定义
注意:引用的部分出现在C++11和C++14的草稿中。
注意:在[dcl.enum]p6
下的C++03中可以找到陈述相同内容但使用不同术语的措辞
注意:为了在本文中保留空间,没有包含整个[decl.enum]p7
详细信息
enum class E : unsigned char { A, B, C };
E x = static_cast<E> (10);
上面我们初始化x
以存储值10
,即使enum class E
的枚举声明中不存在枚举键,这仍然是一个有效的构造。
考虑到以上内容,我们很容易推断出10
不能存储在长度为2
的比特字段中,因此gcc
的警告是准确的。。我们可能试图在我们的位字段中存储它无法表示的值。
示例
enum class E : unsigned char { A, B, C };
struct A {
E value : 2;
};
A val;
val.value = static_cast<E> (10); // OMG, OPS!?
根据C++标准
8对于基础类型为固定的枚举枚举是基础类型的值。
因此,您的枚举值在范围内
std::numeric_limits<unsigned char>::min() - std::numeric_limits<unsigned char>::max()
位字段a定义为
Piece a:2;
无法保存枚举的所有值。
如果您定义一个没有固定基础类型的无范围枚举,那么其值的范围将是
0 - 2
是的,此警告毫无意义,因为GCC已经警告将值分配给截断的位字段(枚举类型(:
warning: conversion from 'Some_Enum' to 'unsigned char:2'
changes value from '(Some_Enum)9' to '1' [-Woverflow]
在警告的位置,只有所有声明的枚举器都可以保存在位字段中才相关。
在底层整数类型范围内的其他值(但与声明的枚举器不对应,btw通常定义良好(不能由字段表示的说法,如果被赋值,在技术上是正确的,但熵为零,这是一个警告。
因此,此警告在GCC 9.3中得到了修正。
IOW、GCC 9.3及更高版本不再警告此类代码。