在下面的C片段中,检查是否设置了16位序列的前两位:
bool is_pointer(unsigned short int sequence) {
return (sequence >> 14) == 3;
}
CLion的Clang-Tidy给我一个“使用带有二进制位运算符的有符号整数操作数”警告,我无法理解为什么。 unsigned short
不够签名吗?
答案 0 :(得分:24)
The code for this check似乎关心按位运算符的操作数是否已签名。导致警告的sequence
不是14
,而是14
,(sequence >> 14u)
无法解决问题。
{{1}}
答案 1 :(得分:6)
我认为整数提升会导致警告。小于int的操作数被扩展为整数,用于算术表达式,该算术表达式已签名。所以你的代码实际上是return ( (int)sequence >> 14)==3;
,它会引发警告。试试return ( (unsigned)sequence >> 14)==3;
或return (sequence & 0xC000)==0xC000;
。
答案 2 :(得分:5)
在clang-tidy中有一个称为hicpp-signed-bitwise
的检查。该检查遵循HIC ++标准的措辞。该标准is freely available表示:
5.6.1。请勿对有符号操作数使用按位运算符
在某些情况下,将带符号操作数与按位运算符一起使用会受到未定义或实现定义的行为的影响。因此,按位运算符应仅与无符号整数类型的操作数一起使用。
HIC ++编码标准的作者误解了C和C ++标准的意图,并偶然或有意地将重点放在了操作数的 type 而不是操作数的 value 上。操作数。
clang-tidy中的check恰好实现了该措辞,以符合该标准。这项检查是not intended to be generally useful,其唯一目的是帮助可怜的人,他们的程序必须符合HIC ++标准中的一项愚蠢规则。
关键点在于,根据定义,不带任何后缀的整数文字的类型为int
,并且该类型被定义为带符号的类型。 HIC ++现在错误地得出结论,正整数文字可能为负,因此可能会调用未定义的行为。
为了比较,C11标准说:
6.5.7按位移位运算符
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为是不确定的。
此措词经过精心选择,并强调正确的操作数的 value 是重要的,而不是其类型。它还涵盖了值太大的情况,而HIC ++标准只是忘记了这种情况。因此,在HIC ++中说1u << 1000u
是可以的,而1 << 3
则不是。
最好的策略是显式禁用此单个检查。 several bug reports for CLion提到了这一点,并且该问题已在此处得到解决。
更新2019-12-16:我问Perforce这种确切措词背后的动机是什么,以及措辞是否是故意的。这是他们的回应:
我们参与创建HIC ++标准的C ++团队研究了您提到的堆栈溢出问题。
简而言之,在HIC ++规则中引用对象类型而不是值是一种有意的选择,以允许更轻松地自动检查代码。对象的类型始终是已知的,而值却不是。
- HIC ++规则通常旨在“确定”。对类型强制执行可确保始终可以进行可确定的检查,即。直接在使用运算符的地方或将带符号的类型转换为无符号的位置。
- 基本原理明确涉及“可能的”未定义行为,因此明智的实现可以排除:
除非确实存在问题,否则
- 恒定不变,
- 未签名的类型被提升为签名的类型。
- 因此,CLion的最佳操作是在升级之前将检查限制为非恒定类型。