C ++强制编译时错误/警告隐式贯穿在交换机中
switch
语句可能会超级有用,但会导致程序员忘记break语句的常见错误:
switch(val) { case 0: foo(); break; case 1: bar(); // oops case 2: baz(); break; default: roomba(); }
你不会明显得到一个警告,因为有时候明显需要掉头。 良好的编码风格build议评论当你的故事是故意的,但有时是不够的。
我很确定这个问题的答案是否定的,但是:如果你的case
确实case
(或者将来会提出)能够让编译器抛出一个错误(或者至less是一个警告!)没有至less有一个break;
或者什么东西// fallthru
的影响? 有一个使用switch
语句的防御性编程选项是很好的。
那么铿锵有-Wimplicit-fallthrough
我不知道,但通过使用“ -Weverything
发现的简单的-Weverything
。 所以对于这个代码,它给了我下面的警告( 看到现场 ):
warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough] case 2: ^ note: insert '[[clang::fallthrough]];' to silence this warning case 2: ^ [[clang::fallthrough]]; note: insert 'break;' to avoid fall-through case 2: ^ break;
我可以find这个标志的唯一文档是在属性参考中说:
clang :: fallthrough属性与-Wimplicit-fallthrough参数一起使用来标注交换标签之间的故意穿透。 它只能应用于任何语句和下一个切换标签之间的执行点处的空语句。 用特定的注释标记这些地方是很常见的,但是这个属性是用一个更严格的注释replace注释,这个注解可以被编译器检查。
并提供了一个如何标记明确的转场的例子:
case 44: // warning: unannotated fall-through g(); [[clang::fallthrough]]; case 55: // no warning
这种使用属性标记明确的穿透具有不便携性的缺点。 Visual Studio
生成一个错误,并且gcc
生成以下警告:
warning: attributes at the beginning of statement are ignored [-Wattributes]
这是一个问题,如果你想使用-Werror
。
我用gcc 4.9
试过,看起来gcc
不支持这个警告:
错误:无法识别的命令行选项“-Wimplicit-fallthrough”
从GCC 7开始 ,支持“ -Wimplicit-fallthrough
并且可以使用__attribute__((fallthrough))
-Wimplicit-fallthrough
__attribute__((fallthrough))
在有意-Wimplicit-fallthrough
下抑制警告。 海湾合作委员会确实承认在某些情况下的“贯穿”评论,但它可以很容易地混淆。
我没有看到为Visual Studio
生成这样的警告的方法。
请注意, Chandler Carruth解释说:“ -Weverything
都不适合生产使用:
这是一个疯狂的团体,从字面上使铿锵的每一个警告。 不要在你的代码中使用它。 它的目的是严格的叮当开发者或探索存在什么样的警告。
但对于确定存在哪些警告很有用。
我总是写一个break;
在每个case
之前,如下:
switch(val) { break; case 0: foo(); break; case 1: bar(); break; case 2: baz(); break; default: roomba(); }
这样,如果break;
眼睛就更加明显了break;
不见了。 最初的break;
我想是多余的,但它有助于保持一致。
这是一个传统的switch
语句,我只是以不同的方式使用了空白,删除了通常在break;
之后的新行break;
并在下一个case
之前。
build议:如果你始终在条款句子之间插入一条空白行,那么人类略读代码就不会看到“中断”
switch (val) { case 0: foo(); break; case 1: bar(); case 2: baz(); break; default: roomba(); }
当个别案例子句中有很多代码时,这不是很有效,但是这往往是一种不好的代码味道。
这是一个强迫恨的答案。
首先, switch
语句是花哨的gotos。 他们可以与其他控制stream程(着名的, 达夫的设备 )相结合,但这里明显的比喻是一个或两个。 这是一个无用的例子:
switch (var) { CASE1: case 1: if (foo) goto END; //same as break goto CASE2; //same as fallthrough CASE2: case 2: break; CASE3: case 3: goto CASE2; //fall *up* CASE4: case 4: return; //no break, but also no fallthrough! DEFAULT: default: continue; //similar, if you're in a loop } END:
我推荐这个吗? 不。事实上,如果你正在考虑这个只是为了诠释一个倒闭,那么你的问题其实是另一回事。
这种代码确实 很清楚,情况1中可能会发生一次跌落,但是正如其他位所显示的那样,这是一种非常强大的技术,也会导致滥用。 如果使用它,请小心。
忘了break
? 那么,你偶尔也会忘记你select的注释。 在更改switch语句时,忘记考虑是否发生故障? 你是一个糟糕的程序员。 在修改switch语句(或者任何代码)时 ,你需要先理解它们。
老实说,我很less犯这种错误(忘记rest) – 当然比我做其他“常见的”编程错误(例如严格的别名)要less。 为了安全起见,我现在做(并build议你这样做)只是写//fallthrough
,因为这至less说明了意图。
除此之外,程序员需要接受的只是一个现实。 在编写代码后校对你的代码,发现偶尔的debugging问题。 那就是生活。