10

我正在使用 Findbugs 扫描第三方源代码(只是在集成到我的之前要小心),并发现以下警告:

long a = b << 32 | c

错误:整数移位 32 模式 id:ICAST_BAD_SHIFT_AMOUNT,类型:BSHIFT,类别:CORRECTNESS

该代码在 0..31 范围之外执行一个常数值的整数移位。这样做的效果是使用整数值的低 5 位来决定要移动多少。这可能不是预期的,而且至少令人困惑。

任何人都可以解释一下上面的确切含义吗?

谢谢!(我是Java编程的新手)

4

2 回答 2

33

来自Java 语言规范

如果左侧操作数的提升类型是 int,则只有右侧操作数的五个最低位用作移位距离。就好像右手操作数经过位逻辑与运算符 & (§15.22.1) 与掩码值 0x1f。因此,实际使用的移位距离始终在 0 到 31 的范围内,包括 0 到 31。

因此,如果 b 是 int,则表达式等同于

long a = b | c;

我非常怀疑这是有意的。应该是

long a = ((long) b << 32) | c;

(如果 b 已经很长,则代码是正确的,并且 FindBugs 对错误有误)。

于 2009-06-21T07:38:54.570 回答
5

编辑:问题几乎肯定源于'b'是'int'而不是'long'这一事实。

在 C 语言中,如果 'b' 是整数而不是 long 并且您左移 32 位,则原始值中的所有位都已被删除,因此整体表达式的结果将与您会的 'c' 相同调用未定义的行为,因此任何结果都是允许的。Java 对事物的定义不同——正如 Rasmus Faber 的评论和选择的答案中所指出的那样——并且会以可以移动的最大位数为模进行超长移位。[这似乎是一种奇怪的经商方式;我可能已经用有它们的语言安排了一个例外。但是,它是明确定义的,这比确切的定义更重要。] 在计算表达式时不会发生对 64 位的强制;它发生在表达式完成并且分配发生时。

对 5 位的引用是……很有趣。这意味着如果您左移 48 位或二进制 110000,则与左移 16 位相同。或者,“ x << n”与“ ”相同x << (n % 32)

于 2009-06-21T07:32:43.867 回答