C++|Visual Studio 2022:新的枚举检查规则

C++|Visual Studio 2022:新的枚举检查规则

文章图片

C++|Visual Studio 2022:新的枚举检查规则

文章图片

C++|Visual Studio 2022:新的枚举检查规则

文章图片

【C++|Visual Studio 2022:新的枚举检查规则】C++|Visual Studio 2022:新的枚举检查规则

实际上 , 我们内部有一个C++静态分析团队 , 他们的主要目标是:让C++开发者尽可能地编写安全的代码 。 静态分析团队努力工作 , 持续地添加代码安全检查规则 , 并积极解决C++开发社区提交的各类高优先级问题 。 感谢各位开发者一直以来给我们提供的使用反馈和建议 。 今天的文章的内容 , 主要是概述了一些关于枚举使用相关的代码检查规则 , 这些规则会指出枚举的误用场景 , 并对现有的枚举检查做出了一些改进 。
概述我们引入了三项检查来找出枚举位操作方面的误用 。 这些检查源于真实产品代码中的发现的Bug 。 我们同时也通过建议使用C11的enum(而不是之前的遗留版本)来对改进检查规则 。 如果你想了解更多信息 , 请参考关于”如何在工程上启用代码检查”的文档 。
按位枚举(Bitwise enumerations)有一些枚举会将它的枚举值定义为2的次方 。 通常这种定义的使用场景是用来实现一个位操作 , 这样就可以方便进行按位合并和检查 。 新的代码检查规则将会尝试检测对于这种枚举的误用 。
但是 , 需要注意了 , 因为没有一个明确的规则能判定一个枚举是否可以看做一个位枚举 , 所以 , 我们的检查依赖于一组启发式方法从源代码中推断出意图 。
下面 , 我们来看一个只有两个元素的枚举:

因为我们不能确定枚举E的值是否是想形成2的次方 (1248…) , 或者只是简单地增加 1 (123 4…) 。如果没有额外的上下文 , 我们无法判断E是否是按位枚举来用于按位运算 , 或者它是否只是一个常规枚举 。
我们再来看下面这个枚举:

在上面的枚举中 , 最后一个枚举常量不是 2 的次方 。在所有相关位都设置的情况下定义一个常量是一种常见的习惯用法 。对于某些正 k , 这些常数通常具有 2^k-1 的值 。我们的检查会将这种形状的枚举视为按位计算 。我们必须小心这两种启发式的相互作用 。
再来看下面两个枚举:

在上面的例子中 , 我们不想将E1视作按位枚举 , 尽管它的最后一个元素的值为 2^2-1 。另一方面 , 我们绝对希望将 E2 视为按位枚举 。
这些启发式方法对于我们测试检查的项目相当有效 。如果你遇到任何误报或误报 , 请告诉我们 。
C26813规则 C26813 将找到使用 operator== 测试按位枚举值的代码模式 。在大多数情况下 , 保存按位枚举值的变量代表一个位域 。要查询是否在此变量中设置了特定的枚举器值 , 应使用按位运算 。不这样做会产生不正确的结果 , 如下图所示:

在对一些真实世界的代码运行此检查后 , 我们还遇到了枚举具有两个值的幂但从未与按位运算一起使用的情况 。在这些情况下 , 更改枚举常量的值以使代码中的意图更清晰可能是个好主意 。
C26827规则 C26827 可以帮助检测我们忘记添加初始化程序的按位枚举中的枚举数常量 。考虑以下示例:

在这里 , 我们在按位运算中使用枚举常量 , 但并非所有常量都具有 2^k 或 2^k-1 的形式 。事实上 , 它的一个常数 D 具有 2^k+1 的形式 。当我们添加一个新常量而不定义它的值时 , 就会发生这种模式 。
但是 , 这个检查存在限制 。它仅适用于范围枚举 , 因为编译器会在静态分析阶段之前将常规枚举转换为整数 。我们正在寻找改进代码内部表示的方法 , 以便对代码的编写方式有更高的准确度 , 这将在未来实现更好的诊断 。
C26828规则 C26828 将标记来自不同枚举的值混合的按位表达式 。考虑以下示例:

这里 BitWiseA 和 BitWiseB 具有重叠值 。我们不太可能希望在同一个按位表达式中同时使用两者 。这可能是拼写错误的结果 。
此检查具有与 C26827 类似的限制 。
对 C26812 的改进规则 C26812 建议 , 在旧版枚举上使用新的 C++11 范围枚举 。长期以来 , 此检查一直是我们产品的一部分 , 但仍有改进的余地 。以前 , 它在其使用站点而不是在其声明处诊断遗留枚举 。这有几个问题: