【问题标题】:Convert two bytes to a signed integer in java在java中将两个字节转换为有符号整数
【发布时间】:2018-12-01 11:27:53
【问题描述】:

简短的问题

有没有办法将两个字节读取为有符号整数?

详细信息和示例

给定java中的两个字节,每个代表一个整数,我们可以将它们转换为它们一起表示的int值:

byte[] byteArray = new byte[4];
byteArray[0] = 0x00;
byteArray[1] = 0x00;
byteArray[2] = .. //a byte representing an integer
byteArray[3] = .. //a byte representing an integer

int i = ((byteArray[2] & 0xff) << 8) | (byteArray[3] & 0xff); 

当两位代表正整数时,它可以完美地工作。但是当两个整数为负时它会失败。 例如当:

byteArray[2] = 0xff; // -1
byteArray[3] = 0xf9; // -7

我明白了:

i = 65529;

这是不正确的。它应该只是 -8 即 0xf8。

我尝试使用 ByteBuffer:

byte[] array = new byte[4];
array[0] = 0x00;
array[1] = 0x00;
array[2] = 0xff;
array[3] = 0xf9;

ByteBuffer buffer = ByteBuffer.wrap(array);
int i = buffer.getInt();

没用。得到相同的结果:

i = 65529

这些只是示例。会有更多字节,它们将代表正整数和负整数。

有没有办法将两个字节作为有符号整数读取并得到正确的结果?

提前致谢。

【问题讨论】:

  • 您可以尝试从您的逻辑中减去 65536,如果为负,则将结果移位,或者您是否正在寻找单行?
  • 我不明白字节和 0xff 部分的需要。该操作的结果始终是第一个操作数...
  • @RayToal 我需要一种方法来处理负字节和正字节。我只提供了两个整数为负数的示例。当然还有其他情况。
  • 改用short,因为int的最左边是0,所以它是一个正数。但是如果你使用short,那么你会得到你想要的负值,因为由于short只有2个字节,最左边的位将是0xFF中最左边的1,使其成为负数。

标签: java arrays byte bytebuffer signed-integer


【解决方案1】:

kotlin 方式

        val low: UByte = bytes[3].toUByte()
        val high: UByte = bytes[4].toUByte()

        return (high.toInt() shl 8) or low.toInt()

【讨论】:

    【解决方案2】:

    在您的情况下,您只需从高字节中删除按位&amp;:

    int i = (byteArray[2] << 8) | (byteArray[3] & 0xff);
    

    &amp; 0xff 正在撤消您想要的符号扩展。 You still need it on the low byte.

    补码扩展的工作方式如下:

    1. 如果设置了较小尺寸数字的最高有效位,

      //    v
          0b1000000_00000000
      
    2. 用 1 填充旧最重要位上方的新位:

      //    vvvvvvvv vvvvvvvv
          0b11111111_11111111_1000000_00000000
      

    只要 byte 或 short 转换为 int 或 long,Java 就会自动执行此操作,byte 上的 &amp; 0xFF 的目的是撤消自动符号扩展。

    如果您无法访问字节,您可以使用算术右移自己进行符号扩展:

    i = (i << 16) >> 16;
    

    或投射到short:

    i = (short) i;
    

    或者各种if测试如:

    if ((i & 0x80_00) != 0) // Is the MSB of the high byte set?
        i |= 0xFF_FF_00_00; // Fill the rest with 1s.
    

    还有:

    if (i > 32767)
        i -= 65536;
    

    【讨论】:

      【解决方案3】:

      两个字节作为有符号整数:

      public class MyClass {
          public static void main(String args[]) {
              byte h = (byte)0xff;
              byte l = (byte)0xf9;
      
              int i = (short) ((h << 8) | l);
              System.out.println(i);
          }
      }
      

      (我将在此处粘贴我在您的问题下所做的评论):

      请改用short,因为int 的最左边位是0,因此它是一个正数。但是如果你使用short,那么你会得到你想要的负值,因为short类型只有2个字节,那么最左边的位将是0xFF中最左边的1,使它成为一个负数。

      【讨论】:

      • 你还需要(l &amp; 0xFF)。否则,当l 为负数时,您最终会以 1 代替高字节。另见stackoverflow.com/q/11380062/2891664。在进行任何类型的算术运算时,Java 总是将 byte 提升为 int(带有符号扩展名)。
      • @Radiodef 我不确定我是否理解。我认为我们谈论的是位操作级别的数字,而不是算术,并且 OP 希望将每个字节的位一个接一个地(一个高位和一个低位)放在一起,无论这些位代表什么解释为 byte 时的负数或正数。这也是一个非常奇怪的操作,因为byte b; b &amp; 0xFF 总是产生一个与b 完全相同的位的int,右边用0 填充,这与简单地将byte 转换为@987654337 相同@,也许我错过了什么。
      • 参见例如:ideone.com/bqMc16。同样,因为 Java 将 byte 转换为带有符号扩展名的 int,这意味着如果设置了 byte 的 MSB,则 int 值在位 8-31 中填充 1。我们使用&amp; 0xFF 从符号扩展中删除 1。 (当您的答案中的short 到int 转换依赖于它工作时,您怎么不知道符号扩展?)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2011-12-27
      • 1970-01-01
      • 2012-10-30
      • 2013-08-15
      • 2023-01-29
      • 2011-04-21
      相关资源
      最近更新 更多