java - 将 CRC8 从 C 转换为 Java

标签 java c crc

我收到一段 C 代码,它计算字节数组的 CRC8 值。 我需要把它翻译成 Java。

这里是C代码:

CRC_POLYNOM = 0x9c;
CRC_PRESET = 0xFF;

unsigned int CRC = CRC_PRESET;
for (i = 0; i < Len; i++)
{
  crc ^= FRAME[i];
  for (j = 0; j < 8; j++)
  {
    if (crc & 0x01)
        crc = (crc >> 1) ^ CRC_POLYNOM;
    else
        crc = (crc >> 1);
  }
}

我在 Java 中做到了这一点:

public static long calculateCRC8(byte[] b, int len) {
  long crc = CRC_PRESET;
  for (int i = 0; i < len; i++) {
    crc ^= b[i];
    for (int j = 0; j < 8; j++) {
      if ((crc & 0x01) == 0)
        crc = (crc >> 1) ^ CRC_POLYNOM;
      else
        crc = crc >> 1;
    }
  }
return crc;
}

对于一个示例字节数组:

byte[] b = new byte[] {1, 56, -23, 3, 0, 19, 0, 0, 2, 0, 3, 13, 8, -34, 7, 9, 42, 18, 26, -5, 54, 11, -94, -46, -128, 4, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 1, -32, -80, 0, 98, -5, 71, 0, 64, 0, 0, 0, 0, -116, 1, 104, 2};

C 代码返回 29,但我的 Java 代码返回 44。 我做错了什么?

我认为这是因为 Java 的仅签名数据类型,那么我该如何解决这个问题?

最佳答案

if (crc & 0x01)

这测试是否设置了最低位。

if ((crc & 0x01) == 0)

这会测试底部位是否清除。

您还应该在 Java 代码中使用无符号右移(即 >>> 而不是 >>,在两个地方),并用 0xff 在返回之前。

编辑最后你需要改变这个:

crc ^= b[i];

到这里:

crc ^= b[i] & 0xff;

但是,您真的应该把它全部扔掉并查找表驱动方法。它是这个速度的八倍。

EDIT 2 表驱动版本,修改后实现java.util.zip.Checksum:

public class CRC8 implements Checksum
{
    private final short init;
    private final short[]   crcTable = new short[256];
    private short   value;

    /**
     * Construct a CRC8 specifying the polynomial and initial value.
     * @param polynomial Polynomial, typically one of the POLYNOMIAL_* constants.
     * @param init Initial value, typically either 0xff or zero.
     */
    public CRC8(int polynomial, short init)
    {
        this.value = this.init = init;
        for (int dividend = 0; dividend < 256; dividend++)
        {
            int remainder = dividend ;//<< 8;
            for (int bit = 0; bit < 8; ++bit)
                if ((remainder & 0x01) != 0)
                    remainder = (remainder >>> 1) ^ polynomial;
                else
                    remainder >>>= 1;
            crcTable[dividend] = (short)remainder;
        }
    }

    @Override
    public void update(byte[] buffer, int offset, int len)
    {
        for (int i = 0; i < len; i++)
        {
            int data = buffer[offset+i] ^ value;
            value = (short)(crcTable[data & 0xff] ^ (value << 8));
        }
    }

    /**
     * Updates the current checksum with the specified array of bytes.
     * Equivalent to calling <code>update(buffer, 0, buffer.length)</code>.
     * @param buffer the byte array to update the checksum with
     */
    public void update(byte[] buffer)
    {
        update(buffer, 0, buffer.length);
    }

    @Override
    public void update(int b)
    {
        update(new byte[]{(byte)b}, 0, 1);
    }

    @Override
    public long getValue()
    {
        return value & 0xff;
    }

    @Override
    public void reset()
    {
        value = init;
    }

    public static void  main(String[] args)
    {
        final int   CRC_POLYNOM = 0x9C;
        final byte  CRC_INITIAL = (byte)0xFF;

        final byte[]    data = {1, 56, -23, 3, 0, 19, 0, 0, 2, 0, 3, 13, 8, -34, 7, 9, 42, 18, 26, -5, 54, 11, -94, -46, -128, 4, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 1, -32, -80, 0, 98, -5, 71, 0, 64, 0, 0, 0, 0, -116, 1, 104, 2};
        CRC8    crc8 = new CRC8(CRC_POLYNOM, CRC_INITIAL);
        crc8.update(data,0,data.length);
        System.out.println("Test successful:\t"+(crc8.getValue() == 29));
    }
}

关于java - 将 CRC8 从 C 转换为 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25284556/

相关文章:

java - 使用 Comparator 接口(interface)排序的问题

用c程序将xml文件转换为wbxml

c - OpenSSL ECB 非 64 位多纯文本

c - C中的通用二叉搜索树

reverse-engineering - 找出 RS232 数据的 CRC 或 CHECKSUM

java - 如何使用 CBZip2OutputStream 压缩多个文件

java - 在居中的 PopupPanel onLoad 中显示 GWT 图像

java - GCM 未在 Android 4.0.4 设备上接收消息

c# - C to C# CRC计算转换器

c++ - 使用 Boost 计算 ECMA-128 64 位 CRC