1

我正在尝试将此 C++ 校验和转换为 Java,但目前我失败了。我究竟做错了什么?

它应该做什么?它应该为OpenGL中的缓冲区返回一个正校验和

这是C部分。

DWORD QuickChecksum(DWORD *data, int size){

if(!data) {
    return 0x0; 
}

DWORD sum;
DWORD tmp;
sum = *data;

for(int i = 1; i < (size/4); i++)
{
    tmp = data[i];
    tmp = (DWORD)(sum >> 29) + tmp;
    tmp = (DWORD)(sum >> 17) + tmp;
    sum = (DWORD)(sum << 3)  ^ tmp;
}

return sum;
}

这是我在 Java 中尝试过的。据我所知,DWORD 是 32 位的,所以我在 long 中使用 int 来获得一个 unsigned int,这应该在 java 中使用 >>> 完成?

我一直在关注这个问题,以至于我对它视而不见。

public static long getChecksum(byte[] data, int size) {
    long sum, tmp;
    sum = getInt(new byte[]{data[0], data[1], data[2], data[3]},true) & 0xFF;
    for(int I = 4; I < data.length; I += 4)
    {
        tmp = getInt(new byte[]{data[I],data[I+1],data[I+2],data[I+3]},true) & 0xFF;
        tmp = (sum >>> 29) + tmp;
        tmp = (sum >>> 17) + tmp;
        sum = (sum << 3) ^ tmp;
    }
    return sum & 0xFF;
}

private static int getInt(byte[] bytes, boolean big) {
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    return bb.getInt();
}

谢谢大家的帮助!

4

3 回答 3

1

明显的错误是,在三个地方,您将输入字和最终校验和与0xff相加,丢失了高 24 位。据推测,您正在尝试将long值减少到 32 位,这需要与0xffffffffL. 在执行此操作之前,您还需要将返回值转换为getInt()long否则您仍然会得到您试图避免的符号扩展。

我的 Java 有点生疏了,但我很确定int只要你使用>>>右移(就像你做的那样),坚持使用 就会得到正确的结果。

您还有一个错误,您在没有检查输入是否为空的情况下无条件地读取前四个字节。

您还需要确保输入具有 4 个字节的倍数;通过检查长度,或者将其更改为使用int[]而不是byte[]像 C 版本那样。当然也不需要size参数,因为 Java 数组会随身携带它们的大小。

以下应该给出与 C 版本相同的结果:

public static int checksum(int[] data)
{
    if (data.length == 0) {
        return 0;
    }

    int sum = data[0];
    for (int i = 1; i < data.length; ++i) {
        int tmp = data[i];
        tmp = (sum >>> 29) + tmp;
        tmp = (sum >>> 17) + tmp;
        sum = (sum << 3)   ^ tmp;
    }

    return sum;
}
于 2012-12-12T11:58:39.607 回答
0

在 Java 中,>>>执行无符号移位,这意味着它将位值 0 插入移入的新位,将负数变为正数。有符号移位>>扩展符号位,负值为 1,因此负数保持负数。

要修复您的代码,至少在您的 & 操作中替换0xFF为。0xFFFFFFFF另外,我认为您可能必须在每次分配时都这样做tmpand sum,而不仅仅是在循环之后一次(不是 100% 肯定,必须通过代码查看是否保留了正确的位,甚至没有额外的位潜入没有ANDing,所以安全总比抱歉好)。

我还会在方法中添加第一件事:

if (data.length & 3 != 0) 
    throw new IllegalArgumentException("byte buffer size not multiple of 4");

此外,我要么删除size参数,要么实际使用它而不是data.length(在检查它是否有效之后),以防数据可能比你想要处理的字节多。

于 2012-12-12T12:00:53.617 回答
0

C++ 版本返回 32 位sum,但您的 Java 版本返回& 0xFF,只剩下 8 位。

  1. 您进行无符号移位>>>并定义所有其他操作,以便它们在有符号 Java 类型中的结果等于对 C++ 无符号类型的相同操作,但对有符号位的解释除外。所以你实际上可以int在这里使用。
  2. 如果继续使用long,则需要使用& 0xFFFFFFFF才能获得 32 位。
于 2012-12-12T12:02:56.023 回答