我正在尝试清理一些 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
我查看了 switch/case/default 的编译器输出,其中使用了很大的范围;我将它与 if/else if/else (源代码)中实现的相同代码进行了比较。
当与 debian 12 中默认的 GCC 12.2 以及debian 使用的相关代码一起使用时,除了名称( Godbolt 的编译器资源管理器)之外,它会生成完全相同的二进制代码。
dpkg-buildflags
幸运的是,现代编译器可以看到简单的内容
if(state == constant) expr; else if(state == other_constant)…
,如果它们很短,就会将它们转换为跳转表。因此,代码与 switch/case 完全相同。这已经发生在-O1
,所以这不是一些危险的优化。而且,更令人惊讶的是,诸如 get 之类的结构
case 5 ... 74:
会转换为与 75 的比较(在跳转表已经处理了低于 5 的情况之后)。所以,实际上,在现代代码中没有理由使用
switch
andcase
,除非您认为它case CONSTANT: … break;
看起来比 更干净if(state == CONSTANT){ … }
。我不知道 - 我也不认为你的编译器会这样做:使用块可以实现更严格的作用域。有一个例外,那就是当然
case:
withoutbreak
允许您基本上模拟goto
withoutgoto
:相当于假设的
(我们都知道忘记 will 会带来的错误;如果你不小心的话,使用会带来同样
break;
的问题。)goto
我希望你明白
switch
对于构建有限状态机的人来说,这确实是一种方便的构造,而不是与范围一起使用 - 与不古老的编译器相比,根本没有任何好处,而且在不明显的控制流中存在大量错误if/else if
来源。因此,我认为,事后看来,现代编译器优化的知识很好,我认为 GNU 的
case
范围特性是考虑不周的,因此警告是明智的。因此,我得出的结论是,消除该警告的正确方法是将
switch
//转换为//构造。case
default
if
else if
else