【问题标题】:Is this warning related to enum class size wrong?这个与枚举类大小有关的警告是否错误?
【发布时间】:2014-03-24 10:13:10
【问题描述】:

警告:

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,它可能必须截断,但这是因为enums 并没有真正与整数和预处理器定义分开。然而enum class 更强大。如果它不足以假设所有Piece 值作为整数将介于 0 和 2 之间(含),则警告是有意义的。否则 GCC 是不必要的挑剔,可能值得邮寄名单说“看,这是一个愚蠢的警告”

以防有人看不到重点

您可以在 2 位数据中存储 4 个不同的值,我只需要 3 个不同的值,因此任何长度为 4 或更少的枚举都应该很好地适合给定的 2 位(并且我的枚举确实“导出”(更好的术语? ) 来自无符号类型)。如果我有 5 个或更多 THEN,我会收到警告。

【问题讨论】:

  • 为什么首先使用枚举作为位字段的基础类型?
  • @KerrekSB 如果我不这样做,我必须定义一个允许unsigned shortPiece 分配的运算符。我在这里是说这个结构的前 2 位应命名为 a 并且在我处理它时应为 Piece 类型。
  • 我和 Alec 的动机相同:我想使用整数的类型化切片(为了清晰和重载)。所有位域都存储可能值的子集(除非声明与类型一样宽);主观上,我不想要警告,因为这是“我的编程风格中的一个理性习语”(我正在从 clang++/MacOS 移植到 gcc/Linux),除非它不符合我声明的所有值(这是关于我实际想要存储在位域中的内容的提示!)。如果有人知道 gcc 命令行选项会专门关闭此警告,请分享。
  • @DanielMGessel 请查看高度评价的“答案”

标签: c++ gcc c++11 enums


【解决方案1】:

gcc发出的警告是准确的,没有必要写邮件到邮件列表要求他们降低警告出现的可能性。

标准规定,基础类型为unsigned char 的枚举不能由长度为2 的位域表示;即使没有具有这种价值的枚举。


标准

枚举的基础值是有效的,即使没有与该值对应的枚举键,标准只规定要存储在枚举中的合法值必须适合基础类型;它没有说明 enum-keys 中必须存在这样的值。

7.2 枚举声明 [dcl.enum]

7... 可以定义一个枚举,其值未由其任何枚举​​器定义。 ...


注意:引用的部分在 C++11 和 C++14 草案中都有。

注意:措辞相同,但使用不同的术语,可以在 C++03 中的 [dcl.enum]p6

下找到

注意:整个[decl.enum]p7 没有被包含在这篇文章中以节省空间。


详情

enum class E : unsigned char { A, B, C };

E x = static_cast<E> (10);

上面我们初始化x以存储值10,即使enum class E的枚举声明中没有enumeration-key,这仍然是一个有效的构造。

考虑到上述情况,我们很容易推断出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!?

【讨论】:

  • enum classes 不一样吗?区别纯粹是语义上的?
  • @AlecTeal 不,scopedunscoped 枚举在询问的内容方面没有区别。
  • 你没有抓住重点。我现在知道警告是有道理的,但我还没有解决我的问题,这篇文章也没有。它与仅包含“否”的帖子一样有用。但肯定会提供更多信息。信息丰富并不意味着它会有用。
  • @AlecTeal 它回答了所述问题,如果您想问其他问题,则必须在创建问题时明确说明。请参见; How to Ask - Stackoverflow.
  • 但是,如果只存储枚举值(或者通常是适合位域的值),它应该可以工作,还是会有未定义的行为?
【解决方案2】:

根据 C++ 标准

8 对于基础类型固定的枚举, 枚举是底层类型的值。

所以你的枚举值在范围内

std::numeric_limits<unsigned char>::min() - std::numeric_limits<unsigned char>::max()

位域a定义为

Piece a:2;

不能保存枚举的所有值。

如果您要定义一个没有固定基础类型的无范围枚举,那么其值的范围将是

0 - 2

【讨论】:

  • 哪个标准? 98、11 还是 14? - 98 肯定是这种情况,就像 C 中的情况一样。
  • @Alec Teal 作用域枚举在 C++ 2011 中引入
  • enumenum class 都默认使用 int 作为底层类型。确定无范围并不意味着匿名?
  • @Alec Teal 标准中没有声明无范围枚举具有默认的基础类型 int。无作用域枚举是没有枚举键类或结构的枚举。
  • 那么我的问题有解决方案吗?我什至不确定使用哪些编译指示来消除警告(它只是说默认启用)
猜你喜欢
  • 1970-01-01
  • 2020-12-16
  • 1970-01-01
  • 2023-03-09
  • 2014-05-12
  • 2012-01-19
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多