C++ 强制编译时错误/警告开关中的隐式失败 [英] C++ Force compile-time error/warning on implicit fall-through in switch

查看:29
本文介绍了C++ 强制编译时错误/警告开关中的隐式失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

switch statements can be super useful, but lead to a common bug where a programmer forgot a break statement:

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

您显然不会收到警告,因为有时明确需要失败.好的编码风格建议在你故意失败时发表评论,但有时这还不够.

You won't get a warning obviously since sometimes fall-through is explicitly desired. Good coding style suggests to comment when your fall-through is deliberate, but sometimes that is insufficient.

我很确定这个问题的答案是否定的,但是:目前(或将来提出)有什么方法可以要求编译器抛出错误(或至少是警告!)如果您的 case 没有至少一个 break; 或影响 //fallthru 的东西?有一个使用 switch 语句的防御性编程选项会很好.

I'm pretty sure the answer to this question is no, but: is there any way currently (or proposed in the future) to be able to ask the compiler to throw an error (or at least a warning!) if your case does not have at least one of break; or something to the effect of // fallthru? It would be nice to have a defensive programming option for using switch statements.

推荐答案

嗯,clang 有 -Wimplicit-fallthrough,我不知道,但使用 -Weverything 发现.因此,对于这段代码,它给了我以下警告(现场观看):

Well clang has -Wimplicit-fallthrough which I did not know about but found by using -Weverything. So for this code it gives me the following warning (see it live):

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; 

我能找到的关于这个标志的唯一文档是 属性参考,上面写着:

The only documentation I can find for this flag is in the Attribute Reference which says:

clang::fallthrough 属性与-Wimplicit-fallthrough 参数来注释开关标签之间的故意失败.它只能应用于空语句放置在任何语句和下一条语句之间的执行点切换标签.通常用特定的标记来标记这些地方评论,但此属性旨在用更多替换评论严格注解,编译器可以检查.

The clang::fallthrough attribute is used along with the -Wimplicit-fallthrough argument to annotate intentional fall-through between switch labels. It can only be applied to a null statement placed at a point of execution between any statement and the next switch label. It is common to mark these places with a specific comment, but this attribute is meant to replace comments with a more strict annotation, which can be checked by the compiler.

并提供了一个如何标记显式失败的示例:

and provides an example of how to mark explicit fall-through:

case 44:  // warning: unannotated fall-through
g();
[[clang::fallthrough]];
case 55:  // no warning

这种使用 属性 来标记显式失败的缺点不便携.Visual Studio 生成错误,gcc 生成以下警告:

This use of an attribute to mark explicit fall-through has the disadvantage of not being portable. Visual Studio generate an error and gcc generates the following warning:

warning: attributes at the beginning of statement are ignored [-Wattributes]

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

which is a problem if you want to use -Werror.

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

I tried this with gcc 4.9 and it looks like gcc does not support this warning:

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

error: unrecognized command line option '-Wimplicit-fallthrough'

GCC 7 开始,<支持 code>-Wimplicit-fallthrough 并且 __attribute__((fallthrough)) 可用于在有意放弃时抑制警告.GCC 确实在某些情况下识别失败"注释,但它可能会被混淆相当轻松.

As of GCC 7, -Wimplicit-fallthrough is supported and __attribute__((fallthrough)) can be used to suppress the warnings when fallthrough is intentional. GCC does recognize "fallthrough" comments in certain scenarios, but it can be confused fairly easily.

我没有看到为 Visual Studio 生成此类警告的方法.

I do not see a way of generating such a warning for Visual Studio.

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

Note, Chandler Carruth explains that -Weverything is not for production use:

这是一个疯狂的组,它确实启用了 Clang 中的每个警告.不要在你的代码上使用它.它严格用于 Clang开发人员或探索存在哪些警告.

This is an insane group that literally enables every warning in Clang. Don't use this on your code. It is intended strictly for Clang developers or for exploring what warnings exist.

但它对于找出存在哪些警告很有用.

but it is useful for figuring out what warnings exist.

在 C++17 中,我们获得了 [dcl.attr.fallthrough]p1:

In C++17 we get the attribute [[fallthrough]] covered in [dcl.attr.fallthrough]p1:

attribute-token fallthrough 可以应用于空语句(9.2);这样的声明是失败的陈述.attribute-token fallthrough 应在每个 attribute-list 中最多出现一次,并且没有 attributeargument-条款应存在.fallthrough 语句只能出现在封闭的 switch 中声明 (9.4.2).在 fallthrough 语句之后执行的下一条语句应该是标记语句,其标签是同一 switch 语句的 case 标签或默认标签.该程序是如果没有这样的陈述,则格式错误.

The attribute-token fallthrough may be applied to a null statement (9.2); such a statement is a fallthrough statement. The attribute-token fallthrough shall appear at most once in each attribute-list and no attributeargument- clause shall be present. A fallthrough statement may only appear within an enclosing switch statement (9.4.2). The next statement that would be executed after a fallthrough statement shall be a labeled statement whose label is a case label or default label for the same switch statement. The program is ill-formed if there is no such statement.

...

[ 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 ]

请参阅使用属性的实时示例.

这篇关于C++ 强制编译时错误/警告开关中的隐式失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆