将 64 位数据转换为带符号的长值

Convert 64bit data to signed long value

我有这样的东西:

byte[0] = 0001 0100 0011 0100  (dec value: 5172)  
byte[1] = 0000 0000 0111 1100  (dec value: 124)  
byte[2] = 0000 0000 0000 0000  (dec value: 0)  
byte[3] = 0000 0000 0000 0000  (dec value: 0)

我想将它们组合起来并在 Java 中形成一个 long 值。怎么做?

这样可以转换吗?

结果 = 0 + (0 x 2^16) + (0 x 2^16) + (124 x 2^32) + (5127 x 2^48)

结果=字节[3] + (字节[2] x 2^16) + (字节[1] x 2^32) + (字节[0] x 2^48)

编辑:让我试着解释得更好。当我打开工具 ModScan32 并连接到我的设备时,我看到了一些寄存器。在这个工具中有不同种类的选项如何显示数据。其中之一是将它们表示为二进制或十进制。当我选择二进制或十进制时,我得到的值与上面示例中的值相同。当我用我的软件读取这些数据时,我得到了完全相同的十进制值(转换后的值)。现在我的问题是,是否有必要将数据保存在 4 个 16 位寄存器中,并且我知道它们的十进制值,从寄存器中组合这些值并获得实际值的正确方法是什么?

你的想法基本没问题。有几点需要注意。

我相信你所追求的结果是 0001010000110100000000000111110000000000000000000000000000000000

这是一个无效的尝试:

    int[] registers = { 5172, 124, 0, 0 };
    long result = registers[0] << 48 | registers[1] << 32 | registers[2] << 16 | registers[3];
    System.out.println(Long.toBinaryString(result));

<< 48表示左移48位,应该够了吧? | 是按位逻辑或,它将任一操作数中的 1 位填充到结果的相同位位置。如果您愿意,可以使用 +

这会打印:

10100001101000000000001111100

我们只有结果的前 32 位,这还不够好。尝试阅读时,请注意 Long.toBinaryString() 不包含前导零。想象一下数字前面有 3 个零。

但是发生了什么?最后 32 位到哪里去了?即使它们全为零。问题是我们在 ints 中进行计算,它们是 32 位,而不是 64 位。编辑:我之前的解释在这一点上并不完全正确。真相是:在int上做<<时,只考虑右操作数的后5位,所以由于48在二进制中是110000,所以只用了10000,所以移位是一样的作为 << 16。类似地 << 32<< 0 相同,完全没有移位。所以 registers[0][1] 最终出现在错误的位位置。当您知道时,解决方案很简单:我们需要在 进行计算之前转换为 long 。现在使用右操作数的最后6位,所以48和32理解为48和32:

    long result = ((long) registers[0]) << 48 | ((long) registers[1]) << 32 | registers[2] << 16 | registers[3];

这次我们得到

1010000110100000000000111110000000000000000000000000000000000

同样,假设前面有 3 个零位,一切都符合预期。

还有一件事。假设您从寄存器中得到一个负值,例如:

    int[] registers = { 5172, -124, 0, 0 };

刚才的计算现在给了我们

11111111111111111111111111000010000000000000000000000000000000000

这次打印的是64位,所以很容易看出开头的1太多了。它们来自 -124 的 int 表示。解决方案是将它们屏蔽掉:

    int[] registers = { 5172, -124, 0, 0 };
    long result = ((long) registers[0] & 0xFFFF) << 48
            | ((long) registers[1] & 0xFFFF) << 32 
            | (registers[2] & 0xFFFF) << 16 
            | (registers[3] & 0xFFFF);
    System.out.println(Long.toBinaryString(result));

0xFFFF 是 16 个 1 位,而 & 是按位逻辑“与”,仅在两个操作数都为 1 位的位置给出结果中的 1 位。现在 -124 被屏蔽为 1111111110000100 所以结果是预期的:

1010000110100111111111000010000000000000000000000000000000000

应该可以了。