我正在使用Findbugs扫描第三方源代码(只是为了在集成之前要谨慎),并发现以下警告:
long a = b << 32 | c
错误:整数移位32个模式ID: ICAST_BAD_SHIFT_AMOUNT,键入:BSHIFT, 类别:正确
代码执行整数移位 超出范围的恒定量 0..31。这样做的效果是使用整数值的低5位 决定转移多少。这个 可能是不希望的,并且 至少令人困惑。
有人可以解释上面究竟是什么意思吗?
谢谢! (我是Java编程的新手)
答案 0 :(得分:32)
来自Java Language Specification:
如果左侧操作数的提升类型为int,则只使用右侧操作数的五个最低位作为移位距离。就好像右手操作数受到按位逻辑AND运算符&amp; (§15.22.1),掩码值为0x1f。因此,实际使用的移动距离始终在0到31的范围内,包括0和31。
因此,如果b是int,则表达式与
相同long a = b | c;
我非常怀疑是什么意思。应该是
long a = ((long) b << 32) | c;
(如果b已经很长,代码是正确的,并且FindBugs误解了这个错误。)
答案 1 :(得分:5)
编辑:问题几乎肯定源于'b'是'int'而不是'long'这一事实。
在C中,如果'b'是一个整数而不是一个long而你向左移动32位,那么原始值中的所有位都被删除了,因此整个表达式的结果将是相同的作为'c',您将调用未定义的行为,因此任何结果都是允许的。 Java以不同的方式定义 - 正如Rasmus Faber的评论和所选答案中所述 - 并且以可以移位的最大位数为模的超长移位。 [做生意似乎很奇怪;我可能已经安排了一个包含它们的语言的例外。但是,它被明确定义,这比定义的确切更重要。]在表达式被评估时,不会发生64位的强制;它在表达式完成并且赋值发生时发生。
对5位的引用是......有趣的。这意味着如果你向左移动,比如48,或二进制110000,则向左移动16相同。或者,“x << n
”与“x << (n % 32)
”相同。