避免虚假的-Wswitch警告

8

让我们有一个值列表(foo.lst):

foo,
bar,
baz,

让我们把它转换为枚举。
enum foo {
  #include "foo.lst"
  _foo_length
};

让我们在 switch 中使用该枚举:

int main(void) {
  enum foo[_foo_length];

  switch(f[0]) {
    case foo: return 0;
    case bar: return 0;
    case baz: return 0;
  }

  __builtin_unreachable();
}

(这段代码很蠢,但可以忽略)

问题:
使用-Wswitch(包括在-Wall中),GCC和Clang(可能还有其他编译器)会发出警告:

警告:枚举值'_foo_length'在switch语句中未被处理[-Wswitch]

解决方法:

  • 禁用-Wno-switch可以隐藏该警告。
    缺点:我们将失去有关switch缺少任何其他case的警告。
  • 添加一个default: unreachable(); case。
    缺点:我们将失去在编译时缺少case的警告,而选择在调试时遇到缺少的情况会导致运行时崩溃。
  • #define _foo_length (baz + 1)替换枚举的最后一个值,使其不再是枚举的一部分。
    缺点:需要手动更新该定义,每次向列表中添加值时都要这样做。某些人肯定会忘记,导致一切都出毛病。

理想情况下,应该有一种方法可以将枚举值标记为不可分配,从而使其在编译器读取可能的值时不产生警告,而不需要预处理器宏需要重复修改。

有类似的东西吗?还有其他我没有想到的选项吗?


由于您正在动态创建枚举,您如何确保switch确实涵盖了所有情况? - Barmar
如果文件没有其中一种情况会发生什么?整个事情让我感觉不对劲。 - Barmar
2
你可以添加一个 case _foo_length: - Barmar
1
@OliverCharlesworth -Wswitch 执行相反的测试。如果 foo.lst 缺少其中一个名称,他将会得到未定义变量错误。但是我想知道为什么他会在 switch 中硬编码名称,当他正在动态加载名称时,似乎存在设计错误。 - Barmar
据我所知,没有gcc开关可以说:“如果我在开关中没有包含XXX,则不要警告我,但我希望对所有其他枚举值进行警告”。 - Support Ukraine
显示剩余4条评论
1个回答

3

使用

case _foo_length:
    unreachable();
    break;

为了处理所有的情况,您可以创建一个宏来简化操作,以避免过于冗长。

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