C#中的CRC32校验失败

3

我试图在C#中实现自己的CRC32函数。我在这里看到了一个优雅的JS解决方案:JavaScript CRC32,因此我想到了以下代码:

internal static class Crc32
    {
        internal static long CalculateCrc32(string str)
        {
            long[] crcTable = Crc32.MakeCrcTable();
            long crc = 0 ^ (-1);

            for (int i = 0; i < str.Length; i++)
            {
                char c = str[i];
                crc = (crc >> 8) ^ crcTable[(crc ^ c) & 0xFF];
            }

            return ~crc; //(crc ^ (-1)) >> 0;
        }

        internal static long[] MakeCrcTable()
        {
            long c;
            long[] crcTable = new long[256];
            for (int n = 0; n < 256; n++)
            {
                c = n;
                for (int k = 0; k < 8; k++)
                {
                    var res = c & 1;
                    c = (res == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
                }
                crcTable[n] = c;
            }

            return crcTable;
        }
    }

问题在于我的解决方案没有返回相同的结果。Console.WriteLine(Crc32.CalculateCrc32("l")); 的结果是1762050814,而JS函数产生的结果是2517025534。JS结果也是正确的。我做错了什么?

你确定你链接的是正确的问题吗?你链接的那个问题是关于字符编码的,而不是JS CRC... - Ron Beyer
你能不能调试一下找到问题所在?转储CRC表并查看是否匹配。在每次计算后转储CRC并查看它们何时分歧等。我们甚至没有你的参考实现来进行比较... 此外,谷歌显示了许多C#实现,你可以将其与你的代码进行比较以找到问题所在。 - Chris
1
有一件事让我感到疑惑,那就是你是否正确地使用Int64来计算CRC32?名称表明应该是32位,这里的实现也是如此:http://sanity-free.org/12/crc32_implementation_in_csharp.html - Chris
是的,问题出在数据类型上。将其更改为uint类型后,它就可以正常工作了。 - Cyan
1个回答

3
问题在于您使用了错误的数据类型。我不熟悉CRC32算法,所以我通过谷歌搜索找到http://sanity-free.org/12/crc32_implementation_in_csharp.html作为参考实现。 我发现他们使用的是uint而不是long。这很有道理,因为我认为CRC32中的32意味着它将返回一个32位数字。 long是一个64位的有符号整数。 如果你把所有的long改成uint,那么我们几乎就得到了一个正常工作的程序。唯一无法运行的一行是c=n,因为它不能隐式地将一个int(n)转换为一个uint(c)。然而,由于我们知道n始终是一个正整数,我们可以把n也改为uint类型。 这样就留下了:
internal static uint CalculateCrc32(string str)
{
    uint[] crcTable = Crc32.MakeCrcTable();
    uint crc = 0xffffffff;
    for (int i = 0; i < str.Length; i++)
    {
        char c = str[i];
        crc = (crc >> 8) ^ crcTable[(crc ^ c) & 0xFF];
    }

    return ~crc; //(crc ^ (-1)) >> 0;
}

internal static uint[] MakeCrcTable()
{
    uint c;
    uint[] crcTable = new uint[256];
    for (uint n = 0; n < 256; n++)
    {
        c = n;
        for (int k = 0; k < 8; k++)
        {
            var res = c & 1;
            c = (res == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
        }
        crcTable[n] = c;
    }

    return crcTable;
}

使用以下代码 Console.WriteLine(Crc32.CalculateCrc32("l"));,将会显示预期的结果 2517025534


我太忙于调试而没有考虑类型。谢谢。 - Cyan
没问题。我真的很喜欢像这样漂亮而自包含的调试挑战。 :) - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接