java 中带符号字节的 CRC32

CRC32 with signed bytes in java

我正在尝试将 C CRC32 代码转换为 java。下面的代码是我想出的。但它的工作方式似乎有所不同。在 C 中计算的预期 CRC32 是 13 82 D8 46) 但下面代码的输出是“最终的 crc 是十六进制 ffffffff83bce823 中的 -2084771805”。谁能告诉我为什么?

C代码

uint32 crc32_update(uint32 crc, const uint8_t *data, uint16 data_len)
{

uint16_t tbl_idx;

while (data_len--) {
    tbl_idx = crc ^ (*data >> (0 * 4));
    crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
    tbl_idx = crc ^ (*data >> (1 * 4));
    crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);

    data++;
}
return crc & 0xffffffff;
}

JAVA代码。

public class crc32trial_3 {


static  final  long crc_table[] = new long[] {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};



public static long crc32_init()
{
    return 0xffffffff;
}

private static  long crc32_update(long crc, byte[] data, int data_len)
 {
     int tbl_idx;

    for(int i = 0 ; i <  data_len ; i ++) {
         tbl_idx = (int)crc ^ (data[i] >> (0 * 4));
         crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
         tbl_idx = (int)crc ^ (data[i] >> (1 * 4));
         crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);

         //data++;
     }

     return crc & 0xffffffff;

 }



 public static void main(String args[])
 {
     long intialcrc = crc32_init();
     long crc;


     System.out.println("the intail crc = " + intialcrc);
     byte[] packets = new byte[]{ 88,0,1,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,1,0,0,0,-1,-1,-1,-1,0,0,-56,-46,-117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,-68,118 };

     byte[] totalLenght = new byte[]{100,0,0,0};
     byte[] totalSettingBlock = new byte[]{2};
      crc = crc32_update(intialcrc,totalLenght,4);
      crc = crc32_update(crc, totalSettingBlock,1);
      int temp = 28 + 72;
      crc = crc32_update(crc,packets, temp);
      long finalcrc = crc;




     System.out.println(" the final crc is " + finalcrc + "  in hex " +  Long.toHexString(finalcrc));

 }


}

您需要在所有十六进制常量末尾添加 "L"。然后我得到 46d81382 作为结果,这很接近,但是你所说的排列是预期的。

首先,C 中的 >> 运算符和 Java 中的运算符并不完全相同。 Java 中的 >> 仅针对 int 和 long 类型定义,它的 总是 有符号移位,与 C 相反,如果左侧表达式是无符号的,则它是无符号的转变是无符号的。 Java 中使用的移位运算符是 >>>。所以当翻译 C 的 usigned >> n 时,在 Java 中它变成了 signed >>> n.

其次,因为 >>(和 >>>)存在 只有 用于 Java 中的 int 和 long,在像 (byte) >> 4 这样的表达式中字节进行到 int first 的扩大转换,并且由于字节被签名,这意味着 符号扩展 到 int,而在 C 中,字节是无符号的,这意味着它们的扩大转换也是未签名的。所以如果字节要被当作unsigned,就必须显式转换成unsigned int(通常称为byte masking):int usigned = (byte expression) & 0xFF;.

而且我不知道 为什么 你选择将 CRC 和 table 声明为 long,其中 int 就足够了。

相应地更改代码给出:

public class crctrial3 {

    static final int crc_table[] = new int[] { 0x00000000, 0x1db71064,
            0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158,
            0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
            0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };

    public static int crc32_init() {
        return 0xffffffff;
    }

    private static int crc32_update(int crc, byte[] data, int data_len) {
        int tbl_idx;

        for (int i = 0; i < data_len; i++) {
            // proper byte masking and shift semantics
            tbl_idx = crc ^ ((data[i] & 0xFF) >>> (0 * 4));
            crc = crc_table[tbl_idx & 0x0f] ^ (crc >>> 4);
            tbl_idx = (int) crc ^ ((data[i] & 0xFF) >>> (1 * 4));
            crc = crc_table[tbl_idx & 0x0f] ^ (crc >>> 4);

            // data++;
        }

        return crc & 0xffffffff;

    }

    public static void main(String args[]) {
        int intialcrc = crc32_init();
        int crc;

        System.out.println("the intail crc = " + intialcrc);
        byte[] packets = new byte[] { 88, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
                -1, -1, -1, 1, 0, 0, 0, -1, -1, -1, -1, 0, 0, -56, -46, -117,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, -1, 0, -68, 118 };

        byte[] totalLenght = new byte[] { 100, 0, 0, 0 };
        byte[] totalSettingBlock = new byte[] { 2 };
        crc = crc32_update(intialcrc, totalLenght, 4);
        crc = crc32_update(crc, totalSettingBlock, 1);
        int temp = 28 + 72;
        crc = crc32_update(crc, packets, temp);
        int finalcrc = crc;

        System.out.println(" the final crc is " + finalcrc + "  in hex "
                + Integer.toHexString(finalcrc));

    }

}

和运行它给出:

the intail crc = -1 the final crc is 1188565890 in hex 46d81382

看起来字节顺序不匹配,如果不知道您用来到达 13 82 D8 46 的代码,就无法判断问题出在哪里。由于 13 82 D8 46 不是 46 D8 13 82 的简单字节顺序反转,我怀疑您最初只是 误读或输入错误 它。