2015-02-09 90 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