为什么带位AND 0xFF的负符号整数会产生正符号整数



我的目标是理解二者的补码。

带符号整数中的CCD_ 1等于CCD_。但是,如果将其与十六进制的0xFF或十进制的11111111进行位"与"运算,则它将等于135

在我看来,这不应该发生,因为顶部字节10000111与结果字节10000111相同

10000111
AND 11111111
------------
10000111 = 135.

我的预期结果是该值不应该改变,它等于-121

我的实际结果是价值发生了变化。

我的猜测是,0xFF就是100001110。因此,顶部字节上的有符号1和下部字节上的无符号

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class WebSocketWorkerThreadTest {
@Test
void SignedToUnsignedInteger() {
byte signed = (byte) 0b10000111;
// If java uses unsigned integer, it should be 135. however, java uses signed integer. Therefore, the outputs will be -121
// 10000111
// ^
// the sign bit. If it exists then the value will be negative.
Assertions.assertEquals(-121, signed);
// 10000111
// 11111111
// --------
// 10000111
int unsigned = signed & 0xFF;
Assertions.assertEquals(135, unsigned);
}
}

应用&运算符时,由于二进制数字提升

signed将提升为int

它不是10000111 & 11111111,而是11111111111111111111111110000111 & 00000000000000000000000011111111,其值是00000000000000000000000010000111(仍然是int(。

这里的MSB是零,因此它是正的。

如果将其强制转换回一个字节,只需要8个LSB,那么该字节将再次为负。

Java将整数(、long和字节(存储在两者的补码中。看见https://en.wikipedia.org/wiki/Two%27s_complement

在这种表示中,任何负数都以一组1位开始,因为值-1210是最低的可表示值,而值1111... 111是-1。因此,当您剪裁前导1位时,您会将数字完全上移到正范围,因为新数字不再以1位开头。

在您的情况下,您使用字节,但字节的值没有您期望的形式。当应用&操作时,它是一个整数,因为您没有将0xFF强制转换为字节。最简单的解决方法是将&运算的结果强制转换为字节,正如另一个答案所建议的那样。

最新更新