Java:将"unsigned"字节转换为int的正确方法

Dmi*_*ank 5 java int byte

我花了几个小时寻找流密码Rabbit的第三方实现中的 bug .有几个错误,但其中一个:

/**
 * @param IV An array of 8 bytes
 */
public void setupIV(final byte[] IV) {
    short[] sIV = new short[IV.length>>1];
    for(int i=0;i<sIV.length;++i) {
        sIV[i] = (short)((IV[i << 1] << 8) | IV[(2 << 1) + 1]);
    }
    setupIV(sIV);
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是字节IV[i << 1]被转换为int,但由于Java没有无符号类型,任何值>= 0x80都是错误的.比方说,字节0xff变成了0xffffffff,而不是0x000000ff上面代码的作者如何预期.

所以我添加了简单的功能:

   private int byte2int(byte b){
      int ret = b;
      if (ret < 0){
         ret += 256;
      }
      return ret;
   }
Run Code Online (Sandbox Code Playgroud)

它有效,但我想知道这是否是正确的方法来做我需要的?这个解决方案似乎有些愚蠢

Sid*_*rth 7

我不确定这会有多大帮助,但你可以通过运行二进制AND操作将一个带符号的字节转换为无符号值0xFF.

进一步采用这种逻辑,你可以通过在int上使用相应的操作数运行类似的AND来检查转换后的溢出.当然,这假设您总是期望正值或零值,或者换句话说无符号数.

(short)(((IV[i << 1] & 0xFF) << 8) | (IV[(2 << 1) + 1] & 0xFF))

Radiodef礼貌地将上述内容融合在一起.

  • @Darkhogg:这条评论具有误导性:不需要强制转换为"int",因为`&`将其操作数提升为`int`(或者`long`,如果其中一个参数属于该类型).因此,表达式`(b&0xFF)`的类型为`int`并产生一个"无符号"值.当然,不应该将此值转换回`byte`,因为这会使它再次"签名". (5认同)