GCC抑制警告“too small to hold all values of”

26

我需要使用作用域枚举,以便将它们作为特定类型传递给我们的串行器。 我已为Enum1的枚举成员提供了明确的整数值。

我已经将符合上述描述的两个作用域枚举放入位域中

enum class Enum1 {
    value1 = 0x0,
    value2 = 0x1,
    value3 = 0x2
};
enum class Enum2 {
    value1 = 0x0,
    value2,
    value3,
 // ...
    value14
};

struct Example {
    Enum1 value1 : 2;
    Enum2 value2 : 6;
}
现在,无论我在哪里使用Example类型,我都会收到警告“'Example::value1'太小,无法容纳所有值'Enum1'”,对于Enum2也是如此。请注意,对于我们定义的值,情况并非如此,我们根本不关心这些值之外的值。
这在我们的构建过程中非常严重,并且项目又大又复杂,我们不想扫描许多这些警告(而且有很多)。
我查看了GCC(G ++)标志,以禁用特定警告。我可以通过命令行传递一个吗?如果可能的话,最好使用警告#pragma在局部禁用它。
在这一点上,改变代码结构的空间很小,但我们真的需要消除这些虚假警告。
编辑:添加标识符更改的作用域枚举。

1
如果Enum1包含超过3个值,则它将无法适应2位。 - nikniknik2016
@Angew:不好意思,这是公司的代码! - jsren
3
请提供一个最小化且完整的可复现问题代码,以便我们帮助您解决该问题。没有可见的代码,我们无法提供帮助。 - Angew is no longer proud of SO
@Angew 我会的,谢谢。我希望有一个编译器标志作为通用解决方案。因此没有提供示例。 - jsren
1
虽然我无法确定它的状态,但有这个gcc错误报告 - nos
显示剩余7条评论
4个回答

18

问题在于作用域枚举总是具有整数基础类型。默认情况下,它是int,但您可以将其更改为任何其他整数类型,例如unsigned char

不幸的是,您无法将基础类型更改为位域,因为它们不是真正的C ++类型。

您可以尝试禁用警告,但是快速浏览G ++代码会显示这些行(gcc/cp/class.c:3468):

  else if (TREE_CODE (type) == ENUMERAL_TYPE
           && (0 > (compare_tree_int
                    (w, TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type))))))
    warning_at (DECL_SOURCE_LOCATION (field), 0,
                "%qD is too small to hold all values of %q#T",
                field, type);

关键在于调用 warning_at(...) 而不是 warning(OPT_to_disable_the_warning, ...)。因此目前没有禁用它的选项。除非自己重新编译编译器!

值得一提的是,CLang++-3.7.1 不会发出此警告。


干杯。说实话,我认为这是一个有用的警告。如果它有更好的描述,那就更好了。而且真的只有第一次出现。我的主要问题是它在每个字段和每个编译单元中都会发生_多次_。尽管只使用了一个g++调用。如何最好地提醒开发人员关于这个问题? - jsren

3
据我所记,具有声明基础类型的枚举可以保存该类型的任何值,而不管定义了哪些枚举常量。由于您可以这样说:
val= enum2{148}

如果您希望代码正常工作,那么这个警告是正确的。您没有声明基本类型,历史上意味着枚举只保证足够大以容纳最低到最高枚举常量所给定的值范围。因此,我不会在这里期望出现任何警告。也许新的enum class即使底层类型自动确定(或编译器认为它需要),也期望完整的范围?您可以尝试使用旧语法的纯枚举,看看是否有任何不同。


4
问题中的枚举类型没有声明底层类型。但实际上规则是,如果有固定的底层类型,那么任何底层类型的值都是有效的枚举器值。而作用域枚举(即enum class)始终具有固定的底层类型,如果未另外指定,则为int - M.M

0
发出这个警告是一个漏洞,因为实际上所有声明的枚举器(值)都可以由位域字段持有。
就像传统的枚举一样,作用域枚举类型的变量仍然可以持有其基础类型的任何值,甚至是不对应一个已声明的枚举器的值。
然而,像这样警告这个问题。
warning: 'some bitfield field' is too small to hold all values of 'enum class FOO'

这是毫无意义的,因为赋一个太大的值,例如

Example x;
x.value1 = Enum1(8);

已经生成了一个-Woverflow警告。


因此,GCC在9.3版本中修复了这个警告

顺便说一下,Clang从未发出过警告。


换句话说,为了在GCC中抑制此警告,您必须升级到GCC 9.3或更高版本。

-1

对于像我这样从搜索中到达这里的其他人:

这个问题只适用于C++11作用域枚举。如果您需要位域枚举,则旧样式枚举没有显式存储大小也可以正常工作:

enum Enum1 {
    Enum1_value1 = 0x0,
    Enum1_value2 = 0x1,
    Enum1_value3 = 0x2
};
enum Enum2 {
    Enum2_value1 = 0x0,
    Enum2_value2,
    Enum2_value3,
 // ...
    Enum2_value14
};

struct Example {
    Enum1 value1 : 2;
    Enum2 value2 : 6;
}

当使用GCC < 9.3编译时,它也适用于基础类型固定的非作用域枚举,例如enum Enum1 : uint8_t - maxschlepzig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接