2016-04-14 270 views
3

我对一个名为OpenBCI的新物联网项目感兴趣,该项目基本上是用于读取和处理脑波和其他生物数据的开源EEG。在他们的docs中,他们声称通过空中传输的数据(通过RFDuino)发送24位数据。到了24位值转换为32位有符号整数,他们提出以下Java友好Processing代码:Java中的24位到32位转换

int interpret24bitAsInt32(byte[] byteArray) { 
    int newInt = (
     ((0xFF & byteArray[0]) << 16) | 
     ((0xFF & byteArray[1]) << 8) | 
     (0xFF & byteArray[2]) 
    ); 

    if ((newInt & 0x00800000) > 0) { 
     newInt |= 0xFF000000; 
    } else { 
     newInt &= 0x00FFFFFF; 
    } 

    return newInt; 
} 

我想我试图了解究竟是怎么回事。让我们的代码的第一个导语:

int newInt = (
    ((0xFF & byteArray[0]) << 16) | 
    ((0xFF & byteArray[1]) << 8) | 
    (0xFF & byteArray[2]) 
); 
  • 为什么是安全的假设有输入3个字节?
  • 0xFF值的重要性是什么?
  • 左移位的目的是什么(<<)?

第二段也是一个有点神秘:

if ((newInt & 0x00800000) > 0) { 
    newInt |= 0xFF000000; 
} else { 
    newInt &= 0x00FFFFFF; 
} 
  • 为什么newInt & 0x008000000x00800000有什么意义?
  • 为什么if-else基于上述操作的阳性与阴性结果?
  • 0xFF0000000x00FFFFFF是什么意思?

我想这个功能有很多handwaving和magic,我想更好地理解!

+0

最后一部分是签名扩展的一个晦涩的方式,else分支是无操作的。更加明显的是'newInt =(newInt << 8) >> 8' – harold

回答

8

为什么安全地假设输入中有3个字节?

24位/ 8位= 3个字节

什么是0xFF的值的意义是什么?

这是一个有点掩码。 0b11111111二进制。在这种情况下,它被用作将字节值转换为int的快速方法。

左移位的目的是什么(< <)?

一旦在上一条指令中检索到int值,它将向左移位16位,以获取int第三个字节的位置(从右边算起)。这是由于字节数组存储big-endian格式的字节,其中MSB最先出现。下一个字节仅移位8位以占用第二个字节的位置,而最后一个字节根本不需要移位,因为它已经在第一个字节中。

为什么newInt & 0x00800000? 0x00800000有什么意义?

那么0x80是获得某个字节的MSB的另一个位掩码。 0x00800000对应于第三字节的MSB(即byteArray[0]中的字节,其在先前过程中被移位了16位)。这也对应于整个24位值的MSB。

为什么if-else基于上述操作的正反结果?

确定24位值的MSB是1还是0会告诉我们它是否为负数或正数,分别为two's complement表示法。

0xFF000000和0x00FFFFFF的意义是什么?

如果数字为它负的24位代表,我们也希望它是否定的,因为在补一个32位值,这就是为什么我们要填补第四和最后一个字节与0b11111111(0xFF的)使用OR运算符。
如果它已经是正的,那么第四个字节可以是0x00,以下3个字节与原始24位值相同 - 用0x00FFFFFF掩码完成。

+0

真棒,真棒答案@James Buck(+1) - 谢谢!只是好奇,如果我在Java中实现它,并且需要单元测试来确认这是否可行或者不是,在哪里可以找到24位有符号整数和它们相应的32位有符号值,以验证测试结果?:-)再次感谢! – smeeb

+0

@smeeb那么你可以选择任意的24位数字,把它们放在二进制补码二进制到十进制转换器中,比如[this](http://www.exploringbinary.com/twos-complement-converter/)。然后你可以把这个相同的二进制数字放在一个3字节的数组中,上面的代码应该把它转换成一个32位的整数,其值与计算器完全相同。该代码将确保任何24位值在转换为32位格式时保留其值。 –