【问题标题】:Why does bitwise AND with byte in JAVA do this?为什么在 JAVA 中按位与字节相加?
【发布时间】:2013-04-27 12:26:32
【问题描述】:

我在搞乱按位运算符,我试图将一个负字节转换为一个无符号的 8 位值,这就是人们的建议:

System.out.println(-20 & 0xFF); //bitwise AND on negative number and 255 

所以,这完美运行,并返回 236,但为什么呢?就我而言:

00010100 //binary representation of -20
11111111 //binary representation of 0xFF or 255
--------
00010100 //it returns the same exact thing, so it's either -20 or 20

为什么有效?我想我错过了一些非常简单的东西,但我似乎无法掌握它。

此外,如果我使用低于 256 的正数执行此操作,它会返回相同的数字。我似乎无法理解 Java 对这些数字的作用。

【问题讨论】:

  • -20 != 20 所以表示也不一样。

标签: java char byte bit-manipulation bit


【解决方案1】:

Java 中的文字采用int 的形式。所以当你说-20 & 0xFF 时,会发生这种情况:

  11111111 11111111 11111111 11101100 //-20 -ve nos are stored in 2's compliment form
& 00000000 00000000 00000000 11111111 // 0xFF 
  -------- -------- -------- --------
  00000000 00000000 00000000 11101100 // 236

由于负值以 2 的补码形式存储,因此得到的值为 236。

当您执行20 & 0xFF 时,会发生这种情况:

  00000000 00000000 00000000 00010100 // 20 -ve nos are stored in 2's compliment form
& 00000000 00000000 00000000 11111111 // 0xFF 
  -------- -------- -------- --------
  00000000 00000000 00000000 00010100 // 20

【讨论】:

  • 啊,我明白了。可能是 2 的恭维形式让我感到困惑。所以让我直截了当地说:如果我保存一个介于 -128 和 -1(含)之间的负数,它会保存为 256 减去该数字的 7 位表示,而第 8 位仅用于表示它是负数还是积极的,对吗?现在,唯一让我有点困惑的是,在第一个示例中,24 个 1 附加在 -20 的开头。为什么是 1,为什么不是 0?这是目前唯一困扰我的事情。
  • @user1007059:如果你有一个byte变量,那么第8位用于存储符号。但是当您有文字时,如上述情况,文字存储为int,无论大小可能有多小。所以当你写-20 & 0xFF时,会创建两个ints,每个都是32位的,MSB,即第32位用于存储符号。在第一个示例中,前面的 1 存在,因为数字是 2 的补码形式,并且在 2 的补码形式中,第一个 1 之前的所有位都被翻转,即 0 变为 1,1 变为 0。
  • 好的,谢谢,我现在了解了大部分内容。我可以继续乱搞比特和字节,而不会觉得自己像个白痴:D
【解决方案2】:

一个字节是一个 8 位的有符号值,可以在 -128 到 127 的范围内。

最左边的位用作符号位。

System.out.println(-20 & 0xFF);与字节无关,这是一个int操作。

-20的二进制表示,作为一个字节是:1110_1100

1110_1100 & 1111_1111 = 1110_1100

如果你想要无符号,有 char 可以玩,但你不会高兴的。实际上,Java 没有无符号。

负数以'2s Complement'形式存储,例如:

1111_1111 == -1

但是为什么呢?

2s补码下做负数,所有位翻转(1s补码)加1(2s补码-两次运算)

所以

 0000_0000 - Zero
-0000_0001 - minus one
 ---------
 1111_1110 - Ones complement - (this would be xor 1111_1111)
+0000_0001 - plus one - we're converting to 2s complement, not doing math
 ---------
 1111_1111 - -1 in 2s complement

【讨论】:

  • 我说“字节”是因为我尝试将 -20 存储在一个字节中,然后执行 & 0xFF 的操作,它确实有效。还有,11101100,不是-108吗?最左边的位代表减号,其余的代表实际数字,即 108。我在这里缺少什么?
  • 只有两个地方缺少 unsigned 确实需要您额外注意:关系运算符和扩展转换。切换到 char 大多是愚蠢的,因为几乎任何对它的操作都会导致 int 带有所有 gorry 签名的问题(但现在隐藏在中间结果中)。了解二进制补码的细节可以让您正确处理无符号数据,即使变量被视为有符号。知识没有足够的替代品,在 java 或任何其他语言中都没有。
  • 我刚开始关注数据类型的大小以及它们是否有符号/无符号等。我一直盲目地使用 int 或 long 作为数字,但现在我搞砸了围绕一些需要对数据类型有更深入了解的东西,这就是我问这个问题的原因。
  • @Durandal 他正在试验比特,而不是设计核电站控制系统。没有“傻”,只有学习。
  • 是的,坠毁阿丽亚娜 5 号火箭的程序员也是如此,因为他们没有费心处理变窄的溢出。猜猜他们也只是在玩比特(en.wikipedia.org/wiki/…)。我称之为提供建议(切换到字符),这会导致比解决“愚蠢”更多的麻烦。只是我的意见。
猜你喜欢
  • 2018-11-29
  • 2015-07-06
  • 2015-08-11
  • 1970-01-01
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
相关资源
最近更新 更多