在以下 C 代码片段中,检查 16 位序列的前两位是否已设置:
bool is_pointer(unsigned short int sequence) {
return (sequence >> 14) == 3;
}
CLion 的 Clang-Tidy 给了我一个“使用带二进制位运算符的有符号整数操作数”警告,我不明白为什么。unsigned short
未签名还不够吗?
在以下 C 代码片段中,检查 16 位序列的前两位是否已设置:
bool is_pointer(unsigned short int sequence) {
return (sequence >> 14) == 3;
}
CLion 的 Clang-Tidy 给了我一个“使用带二进制位运算符的有符号整数操作数”警告,我不明白为什么。unsigned short
未签名还不够吗?
在 clang-tidy 中有一个名为hicpp-signed-bitwise
. 此检查遵循 HIC++ 标准的措辞。该标准是免费提供的,并说:
5.6.1。不要使用带符号操作数的位运算符
在某些情况下,使用带按位运算符的有符号操作数会受到未定义或实现定义的行为的影响。因此,位运算符只能用于无符号整数类型的操作数。
HIC++ 编码标准的作者误解了 C 和 C++ 标准的意图,并且无意或有意地关注操作数的类型而不是操作数的值。
clang-tidy 中的检查正是执行此措辞,以符合该标准。该检查并不打算普遍有用,其唯一目的是帮助那些程序必须符合 HIC++ 标准中的一条愚蠢规则的可怜人。
关键点是,根据定义,没有任何后缀的整数文字属于 type int
,并且该类型被定义为有符号类型。HIC++ 现在错误地得出结论,正整数文字可能是负数,因此可能会调用未定义的行为。
为了比较,C11 标准说:
6.5.7 移位运算符
如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。
这个措辞是经过精心挑选的,并强调正确操作数的值很重要,而不是它的类型。它还涵盖了值太大的情况,而 HIC++ 标准只是忘记了这种情况。因此,1u << 1000u
在 HIC++ 中说是可以的,而1 << 3
不是。
最好的策略是明确禁用这个单一检查。有几个关于 CLion 的错误报告提到了这一点,并且正在那里得到修复。
2019-12-16 更新:我问 Perforce 这个确切措辞背后的动机是什么,以及措辞是否是故意的。这是他们的回应:
我们参与创建 HIC++ 标准的 C++ 团队查看了您提到的 Stack Overflow 问题。
简而言之,在 HIC++ 规则中引用对象类型而不是值是一种有意选择,可以更轻松地自动检查代码。对象的类型总是已知的,而值则不知道。
- HIC++ 规则通常旨在“可判定”。强制执行该类型可确保始终可以进行可判定的检查,即。直接在使用运算符的地方或将有符号类型转换为无符号的地方。
- 基本原理明确提到“可能的”未定义行为,因此明智的实现可以排除:
- 常量,除非确实存在问题,并且,
- 提升为有符号类型的无符号类型。
- 因此,对于 CLion,最好的操作是在提升之前将检查限制为非常量类型。
我认为整数提升会导致警告。对于带符号的算术表达式,小于 int 的操作数被扩展为整数。所以你的代码是有效return ( (int)sequence >> 14)==3;
的,这导致了警告。尝试return ( (unsigned)sequence >> 14)==3;
或 return (sequence & 0xC000)==0xC000;
。