clang-tidy中有一个名为hicpp-signed-bitwise的检查规则,它遵循HIC++标准的措辞。该标准可以
免费获取,其中规定:
5.6.1 不要对带符号的操作数使用按位运算符。
使用带符号操作数的按位运算符在某些情况下会导致未定义或实现定义的行为。因此,按位运算符只应与无符号整数类型的操作数一起使用。
HIC++编码标准的作者误解了C和C++标准的意图,并错误地将重点放在操作数的
类型而不是
值上。
clang-tidy中的这个检查规则严格实现了这个措辞,以符合该标准。该检查规则
并不是通用的,它的唯一目的是帮助那些必须符合HIC++标准的可怜程序员遵守这个愚蠢的规则。
关键问题在于,根据定义,在没有任何后缀的整数字面量中,类型为
int
,而该类型被定义为带符号类型。HIC++标准现在错误地得出结论,即正整数字面量可能是负数,因此可能会
引发未定义行为。
为了比较,C11标准的规定如下:
6.5.7 位移运算符
如果右操作数的值为负数或者大于等于提升后的左操作数的宽度,则行为未定义。
这个措辞是经过精心选择的,强调右操作数的值很重要,而不是类型。它也覆盖了一个过大的值的情况,而HIC++标准只是忘记了这种情况。因此,在HIC ++中说1u << 1000u
是可以的,而1 << 3
则不行。
最好的策略是明确禁用此单个检查。有几个CLion的错误报告提到了这一点,并且正在修复。
更新2019-12-16:我问Perforce这个精确措辞背后的动机是什么以及这个措辞是否是有意的。以下是他们的回答:
我们参与创建HIC ++标准的C ++团队已经查看了您提到的Stack Overflow问题。
简而言之,在HIC++规则中引用对象类型而不是值是一种有意的选择,以便更轻松地自动检查代码。对象的类型始终已知,而值则不是。
- HIC++规则总体上旨在“可决定性”。 对类型进行强制执行,以确保始终可以进行可决定性检查,即直接在使用运算符的地方或将有符号类型转换为无符号类型的地方。
- 基本原理明确提到了“可能”的未定义行为,因此合理的实现可以排除以下情况:
- 常量,除非肯定存在问题
- 将无符号类型提升为有符号类型。
- 因此,对于CLion而言,最佳操作是将检查限制在升级之前的非常量类型。