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问题。 那就是生活。