在安卓/Java中的校验和计算

8
我在Android/Java中编写了一个校验和计算函数,函数如下:
void CalculateCheckSum( byte[] bytes ){
     short CheckSum = 0, i = 0;
     for( i = 0; i < bytes.length; i++ ){
        CheckSum = (short) ((short)CheckSum + (short)bytes[i]);
     }

     Log.i("Checksum", Integer.toHexString(CheckSum));
}

计算校验和的输入值为0xEF,0x01,0xEF,0x01,0x33,0x0C,0xB8,0xE5,0xFC,0x34,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF。我手动计算出的校验和值为0xCE4。但使用上述函数后,得到的答案为0xFFFFFFE4。请问我的计算中是否有错误,如果有,请纠正我。

谢谢。

6个回答

2
使用调试器来调试你的代码。但一般情况下,即使你使用int或long,如果你不断添加内容,它也很可能在某个时刻溢出,导致你得到意外的结果。最好使用标准校验和算法或已有的类,如CRC32或Adler31。至于你的代码,你似乎把结果当作整数处理,那么为什么要先转换为short呢?
Java使用int进行所有算术计算,因此你的byte会被转换为int,而那些无法适应byte的int将会看起来像这样:ffffffef(-17)。自然地,你只需要实际的byte值,所以你需要使用(0xff & b)将其他部分清零。因此,你的循环变成了这样:
  int checkSum = 0;

  for(byte b : bytes){
    checkSum += (0xff & b);
  }

我想向一个使用上述校验和方法进行计算的嵌入式设备发送一些数据包,因此我无法更改CRC32或其他内容。 - Riskhan

2
这里的问题在于对 bytes[i] 进行了 (short) 强制类型转换,这会扩展符号位。你应该把 (short)bytes[i] 改成 (bytes[i] & 0xff)。这样可以得到正确的答案。
与大多数其他答案相反,这与字节溢出无关。你也不必改变数组类型。

1

如aprian所述,虽然字节具有8个位用于表示十六进制值,但它只能存储-128至127之间的值。因此,一个快速简单的解决方案是使用更大的原始类型,例如short

short shorts[] = {0xEF, 0x01, 0xEF, 0x01, 0x33, 0x0C, 0xB8, 0xE5, 0xFC, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

int checkSum = 0;

for( short s : shorts){
    checkSum = checkSum + s;
}

System.out.println("Checksum: " + Integer.toHexString(checkSum));

这给了我输出:

Checksum: ce4

当然,这意味着您可能需要事先转换您的字节数组


这仍然会进行符号扩展。你必须进行掩码处理。 - user207421

1

byte 根据 Java Docs 的定义:

一个 byte 的值范围在 2^(-7)(2^7)-1 之间(-128 到 127)。

但是你的值 0xEF(十进制为 239)已经超出了 byte 的限制。这就是导致求和结果错误的原因。


在Java中,支持8位值(即0-255)的任何数据类型。 - Riskhan
据我所知,Java中没有“unsigned”原始类型。但是您可以找到其他提供“unsigned”类型的依赖项。 - Aprian
1
请尝试此链接 - Aprian
1
0xEF可以放进一个字节,但当你在表达式中使用它时,它只会取值为-17。这本身不会干扰计算。 - user207421

0

终于我得到了...

已经修正的代码

void CalculateCheckSum( byte[] bytes ){
         short CheckSum = 0, i = 0;
         for( i = 0; i < bytes.length; i++){
              CheckSum += (short)(bytes[i] & 0xFF);
         }
         Log.i("Checksum", Integer.toHexString(CheckSum));
    }

感谢 Aprian 和其他人


感谢Aprian?他完全错了,他没有给你这个代码。只有两个答案给了你这个代码,你应该接受其中一个,而不是你自己的。当其他人已经提供了这些答案时,发布自己的答案是浪费时间和空间。 - user207421

-1

如果你要进行转换,应该使用整数作为输入:

    String CalculateCheckSum( Integer[] bytes ){
        Integer CheckSum = 0, i = 0;
        for( i = 0; i < bytes.length; i++ ){
            CheckSum += bytes[i];
        }
        return Integer.toHexString(CheckSum);
    }

这将返回预期的0xCE4,希望这能解决你的问题。


1
但是他没有整数或Integers作为输入。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接