2015-02-09 30 views
0

我想将C CRC32代码转换为java。下面的代码就是我想到的。但它似乎工作方式不同。在C中计算的期望CRC32是13 82 D8 46),但下面的代码的输出是“最后的crc是-2084771805 in hex ffffffff83bce823”。有人能告诉我为什么吗?CRC32与在java中签名的字节

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)); 

} 


} 
+3

['java.util.zip.CRC32'](http://docs.oracle.com/javase/8/docs/api/java/util/zip/CRC32.html)确实存在。 [代码可用](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/zip/CRC32.java#CRC32) 。 – 2015-02-09 08:26:52

+0

然后向右移动0 * 4会产生nohing。你有没有错误地复制你的源代码? – EJP 2015-02-09 08:51:05

+0

我试过但crc.reset()将初始值设置为0,但我要求它是-1。 – Developer 2015-02-09 09:05:40

回答

1

您需要在所有十六进制常量末尾加“L”。结果,我得到了46d81382,这是接近的,但是你所说的是预期的排列。

0

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

第二,由于>>(和>>>)存在为int和长在Java中,在像(byte) >> 4表达式中的字节进行扩大转换到int 第一,而作为字节被签署它意味着符号扩展为int,而在C字节中是无符号的,这表示它们的扩展转换也是无符号的。因此,如果该字节被视为无符号,则必须将其明确转换为无符号整型(通常称为字节掩码):int usigned = (byte expression) & 0xFF;

而且我不知道为什么选择申报CRC和表作为,其中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我怀疑你原来只是误读或打错了而已。

+0

'tbl_idx'的'>>>'可以和原来的'>>'一样,因为索引是&0x0f'ed。如果你用'int's而不是'long',那么在'crc >>> 4'中确实需要'>>>'。在我的答案中对代码的最小改变是简单地将所有的常量变长并且保持变量很长,这样就避免了不必担心有符号变化的问题。那么你也不需要返回的'crc'上的'&0xffffffff'。 – 2015-02-09 19:42:39

+0

@MarkAdler是的,你是绝对正确的;它可以用你最小的变化进行工作。我刚刚通过机械代码(称之为窥视孔翻译)。 crc&0xffffffff是来自我应该*删除的原始代码的剩余部分,但根本没有注意到。由于我将crc的声明更改为int,所以它什么都不做了。 – Durandal 2015-02-10 19:37:28