只允许在 gcc 中切换范围

只允许在 gcc 中切换范围

我正在尝试清理一些 C 代码并构建一个 Debian 软件包。 makefile 设置为使用 -Wall 但 debuild 使用 -Wpedantic 。

碰巧这是“一件好事”,因为代码将数据指针转换为函数指针(ISO C 中不允许并且非常危险......在某些体系结构上数据和代码可能位于不同的地址空间)

然而,代码还在 switch 语句中使用范围,这些是 gcc(和 clang)扩展,因此 -Wpedantic 会出现问题。

case QNAP_PICSTS_SYS_TEMP_0 ... QNAP_PICSTS_SYS_TEMP_70:

(#define 不是枚举)

我收集开关范围的使用在内核中很常见,我可以重新编码它以使用带有一些 if/else 逻辑的默认值,但这实际上会更慢(跳转表与代码)

那么 1 是否有一个选项只允许此功能,2(为了奖励积分)我如何在 Debian 软件包规则中设置它?

选项在这里:

http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Warning-Options.html

答案1

我查看了使用大范围的 switch/case/default 的编译器输出;我将它与 if/else if/else 中实现的相同代码进行了比较(源代码)。

除了名称之外,它产生完全相同的二进制代码(Godbolt 的编译器浏览器),当与 debian 12 中默认的 GCC 12.2 一起使用时,以及与dpkg-buildflagsdebian 使用的相关内容一起使用时。

幸运的是,现代编译器可以看到简单的内容if(state == constant) expr; else if(state == other_constant)…,如果它们很短,就会将它们转换为跳转表。因此,代码与 switch/case 完全相同。这已经发生在-O1,所以这不是一些危险的优化。

而且,更令人惊讶的是,诸如 get 之类的结构case 5 ... 74:会转换为与 75 的比较(在跳转表已经处理了低于 5 的情况之后)。

所以,实际上,在现代代码中没有理由使用switchand case,除非您认为它case CONSTANT: … break;看起来比 更干净if(state == CONSTANT){ … }。我不知道 - 我也不认为你的编译器会这样做:使用块可以实现更严格的作用域。

有一个例外,那就是当然case:withoutbreak允许您基本上模拟gotowithout goto

switch(state) {
case 1: 
  value += 0.2f;
case 2:
  retval = 1.0f/value;
  break
// …
}

相当于假设的

if (state == 1) {
  value += 0.2f;
  goto label_in_two;
}
else if(state == 2) 
  label_in_two:
  retval = 1.0f/value;
}

(我们都知道忘记 will 带来的错误;如果你不这样做,break;使用 will 会带来同样的问题goto非常小心。)

我希望你明白switch对于构建有限状态机的人来说,这确实是一种方便的构造,而不是与范围一起使用 - 与不古老的编译器相比,根本没有任何优势,if/else if而且在不明显的控制流中存在大量错误来源。

因此,我认为,事后看来,现代编译器优化的知识很好,我认为 GNU 的case范围特性是考虑不周的,因此警告是明智的。

因此,我得出的结论是,消除该警告的正确方法是将//switch转换为//构造。casedefaultifelse ifelse

相关内容