简体   繁体   中英

CRC32 with signed bytes in java

I am trying to convert a C CRC32 code to java. The below code is what I came up with. But it seems to work differently. The expected CRC32 calculated in C is 13 82 D8 46) but the output for the below code is " the final crc is -2084771805 in hex ffffffff83bce823". Can someone tell me why?

C code

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 code.

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

 }


}

You need "L" at the end of all of your hex constants. Then I get 46d81382 as the result, which is close to, but a permutation of what you said is expected.

First, the >> operator in C and in Java are not exactly the same thing. The >> in Java is only defined for the type int and long, and its always a signed shift, opposed to C where it is unsigned if the left hand expression is unsigned the shift is unsigned. The usigned shift operator in Java is >>> . So when translating C's usigned >> n , in Java it becomes signed >>> n .

Second, since >> (and >>>) exists only for int and long in Java, in an expression like (byte) >> 4 the byte undergoes a widening conversion to int first , And as byte is signed it means sign extension to int, whereas in C bytes are unsigned meaning their widening conversion is unsigned too. So if the byte is to be treated as unsigned, it must be explicitly converted into an unsigned int (commonly called byte masking): int usigned = (byte expression) & 0xFF; .

And I have no idea why you chose to declare CRC and table as long , where int would perfectly suffice.

Changing the code accordingly gives:

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

    }

}

And running it gives:

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

Looks like there is a mismatch in the byte order, without knowing the code you used to arrive at your 13 82 D8 46 there is no way of telling where the problem lies. Since 13 82 D8 46 is not a simple byte order reversal of 46 D8 13 82 I suspect you originally simply misread or mistyped it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM