C++强制编译时错误/警告在交换机中隐式掉落

Bar*_*rry 53 c++ compiler-warnings switch-statement

switch 语句可能非常有用,但会导致程序员忘记break语句的常见错误:

switch(val) {
    case 0:
        foo();
        break;
    case 1:
        bar();
        // oops
    case 2:
        baz();
        break;
    default:
        roomba();
}
Run Code Online (Sandbox Code Playgroud)

你不会明显得到警告,因为有时明确需要通过.良好的编码风格建议在你的堕落是故意的时候发表评论,但有时这是不够的.

我很确定这个问题的答案是否定的,但是:如果你case不这样做,那么当前(或将来会提出)是否能够让编译器抛出错误(或者至少是警告!)至少有一种break;或某种效果// fallthru?使用switch语句有一个防御性编程选项会很好.

Sha*_*our 67

好铿锵有-Wimplicit-fallthrough哪些我不知道但通过使用找到-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; 
Run Code Online (Sandbox Code Playgroud)

我可以在此标志中找到的唯一文档位于" 属性参考"中,其中说明:

clang :: fallthrough属性与-Wimplicit-fallthrough参数一起使用,用于注释switch标签之间的故意直通.它只能应用于放置在任何语句和下一个开关标签之间的执行点的空语句.通常使用特定注释标记这些位置,但此属性旨在用更严格的注释替换注释,编译器可以检查注释.

并提供了如何标记显式掉落的示例:

case 44:  // warning: unannotated fall-through
g();
[[clang::fallthrough]];
case 55:  // no warning
Run Code Online (Sandbox Code Playgroud)

这种使用属性来标记显式的直通性具有不可移植的缺点.Visual Studio生成错误并gcc生成以下警告:

warning: attributes at the beginning of statement are ignored [-Wattributes]
Run Code Online (Sandbox Code Playgroud)

如果你想使用这是一个问题-Werror.

我试过这个,gcc 4.9看起来gcc不支持这个警告:

错误:无法识别的命令行选项'-Wimplicit-fallthrough'

GCC 7开始,-Wimplicit-fallthrough支持__attribute__((fallthrough))并可用于在有意进行跌穿时抑制警告.GCC确实在某些情况下识别出"通过"评论,但它可以很容易地混淆.

我没有看到产生这种警告的方法Visual Studio.

请注意,Chandler Carruth解释说这-Weverything不适合生产用途:

这是一个疯狂的团体,从字面上实现了Clang的每一个警告.不要在代码中使用它.它仅供Clang开发人员使用,或用于探索存在的警告.

但它有助于弄清楚存在什么警告.

C++ 17的变化

在C++ 17中,我们得到[dcl.attr.fallthrough] p1中涵盖的属性[[fallthough]]:

属性标记可以应用于null语句(9.2); 这样的陈述是一个突破性的陈述.属性 - 标记通过在每个属性列表中最多出现一次,并且不存在attributeargument-子句.fallthrough语句只能出现在封闭的switch语句中(9.4.2).在fallthrough语句之后执行的下一个语句应该是带标签的语句,其标签是同一switch语句的case标签或default标签.如果没有这样的声明,该计划就是不正确的.

...

[ Example:
void f(int n) {
void g(), h(), i();
switch (n) {
  case 1:
  case 2:
    g();
    [[fallthrough]];
  case 3: // warning on fallthrough discouraged
    h();
  case 4: // implementation may warn on fallthrough
    i();
    [[fallthrough]]; // ill-formed
  }
}
—end example ]
Run Code Online (Sandbox Code Playgroud)

使用属性查看实时示例.

  • [[fallthrough]]现在是[官方C++ 17注释](http://en.cppreference.com/w/cpp/language/attributes),所以希望更多编译器在语句失效时添加对可选警告的支持这个注释. (6认同)
  • 这就是为什么`-Weverything`(GCC人们显然不愿意模仿)是如此有用.不,开发人员可能不会在用于编译其生产代码的"官方"警告集中使用它,但是偶尔运行代码库来查看是否有任何真正有用的警告是非常有帮助的. (2认同)

Aar*_*aid 12

我总是写break;每之前case,如下所示:

switch(val) {
    break; case 0:
        foo();
    break; case 1:
        bar();
    break; case 2:
        baz();
    break; default:
        roomba();
}
Run Code Online (Sandbox Code Playgroud)

这样,如果break;缺少一个,那么对眼睛来说就更加明显了.break;我认为最初是多余的,但它有助于保持一致.

这是一个传统的switch陈述,我只是以不同的方式使用空格,删除通常在a之后break;和之前的新行case.

  • 哇,这太可怕了 (16认同)
  • 怎么样`#define CASE break; case`?;) (11认同)
  • @FredOverflow:这会破坏制作"休息"的目的,在视觉上更加突出. (6认同)
  • @FredOverflow我发现更改本机命令的定义有点干扰. (4认同)
  • 你在秋天案件中做了什么?只是省略"休息"? (3认同)

zwo*_*wol 6

建议:如果你一直在case子句之间加上一个空行,那么人们在查看代码时就会看到没有'break'变得更加明显:

switch (val) {
    case 0:
        foo();
        break;

    case 1:
        bar();

    case 2:
        baz();
        break;

    default:
        roomba();
}
Run Code Online (Sandbox Code Playgroud)

当个别case子句中有很多代码时,这并不是那么有效,但这本身往往是一个糟糕的代码味道.