【问题标题】:C zlib crc32 and Python zlib crc32 doesn't matchC zlib crc32 和 Python zlib crc32 不匹配
【发布时间】:2015-03-18 08:34:59
【问题描述】:

我在 Python 和 C 中使用 crc32 进行了一些试验,但结果不匹配。

C:
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>

#define NUM_BYTES 9

int
main(void)
{

  uint8_t bytes[NUM_BYTES] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

  uint32_t crc = crc32(0L, Z_NULL, 0);

  for (int i = 0; i < NUM_BYTES; ++i) {
    crc = crc32(crc, bytes, 1);
  }

  printf("CRC32 value is: %" PRIu32 "\n", crc);
}

给出输出CRC32 value is: 3136421207

Python

In [1]: import zlib
In [2]: int(zlib.crc32("123456789") + 2**32)
Out[2]: 3421780262

在 python 中,我添加 2**32 以“强制转换”为无符号整数。

我在这里错过了什么?

[编辑 1]

现在我已经尝试过

In [8]: crc = 0;
In [9]: for i in xrange(1,10):
   ...:     crc = zlib.crc32(str(i), crc)
   ...:     
In [10]: crc
Out[10]: -873187034
In [11]: crc+2**32
Out[11]: 3421780262

和

int
main(void)
{

  uint32_t value = 123456789L;

  uint32_t crc = crc32(0L, Z_NULL, 0);

  crc = crc32(crc, &value, 4);

  printf("CRC32 value is: %" PRIu32 "\n", crc);
}

还是不一样的结果。

【问题讨论】:

    标签: python c zlib crc32


    【解决方案1】:

    您的原始 C 和 Python 代码 sn-ps 存在问题。至于您的第二个 C sn-p,我没有尝试编译它,但它不可移植,因为 int 中的字节顺序取决于平台。所以它会根据 CPU 的endianness 给出不同的结果。

    正如 Serge Ballesta 所提到的,一个问题是 {1, 2, 3, 4, 5, 6, 7, 8, 9} 和 {'1', '2', '3', '4', '5', '6', '7', '8', '9'} 之间的区别。另一个问题是原始 C 代码中的循环实际上并未扫描数据,因为您没有在循环中使用 i,正如 bav 所述。

    crctest.c

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <zlib.h>
    
    #define NUM_BYTES 9
    
    // gcc -std=c99 -lz -o crctest test.c
    
    void do_crc(uint8_t *bytes)
    {
        uint32_t crc = crc32(0L, Z_NULL, 0);
    
        for (int i = 0; i < NUM_BYTES; ++i)
        {
            crc = crc32(crc, bytes + i, 1);
        }
    
        printf("CRC32 value is: %lu\n", crc);
    }
    
    int main(void)
    {
        uint8_t bytes0[NUM_BYTES] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        uint8_t bytes1[NUM_BYTES] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
    
        do_crc(bytes0);
        do_crc(bytes1);
    }
    

    输出

    CRC32 value is: 1089448862
    CRC32 value is: 3421780262
    

    crctest.py

    #! /usr/bin/env python
    
    import zlib
    
    def do_crc(s):
        n = zlib.crc32(s)
        return n + (1<<32) if n < 0 else n
    
    s = b'\x01\x02\x03\x04\x05\x06\x07\x08\x09'
    print `s`, do_crc(s)
    
    s = b'123456789'
    print `s`, do_crc(s)
    

    输出

    '\x01\x02\x03\x04\x05\x06\x07\x08\t' 1089448862
    '123456789' 3421780262
    

    编辑

    这是在 Python 中处理转换的更好方法:

    def do_crc(s):
        n = zlib.crc32(s)
        return n & 0xffffffff
    

    有关此主题的更多信息,请参见此处的答案:How to convert signed to unsigned integer in python。

    【讨论】:

    • 很好的答案,谢谢。通过将其他答案中的部分拼凑在一起,我几乎到了那里,但这是金色的。
    • 谢谢!有关处理 Python 缺少 unsigned int 类型的替代方法,请参阅我的更新。
    • gcc -std=c99 -lz -o crctest test.c 给出undefined references,应该是gcc -std=c99 -o crctest test.c -lz
    【解决方案2】:

    根据www.lammertbies.nl对CRC计算和C例程有详细的参考,0xCBF43926中的ASCII字符串123456789的CRC32,即3421780262作为十进制形式的无符号32整数。

    这意味着您的 Python 计算是正确的,但要在 C 中获得相同的结果,您应该编写

    uint8_t bytes[NUM_BYTES] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
    uint32_t crc = crc32(0L, Z_NULL, 0);
    

    或者,如果您想要的确实是uint8_t bytes[NUM_BYTES] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 的crc 32,则必须在python 2.x 中使用:

    s = ''
    for i in range(10):
        s += chr(i)
    s
    

    输出:'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t'

    然后

    zlib.crc32(s)
    

    输出:1164760902

    注意:在 python 3.x 中,你会写:s = bytes(range(10))

    【讨论】:

      【解决方案3】:

      你的第一个 c-sn-p 的精确副本给出了相同的结果:

      >>> bytes = [chr(i) for i in range(1, 10)]
      >>> crc = zlib.crc32('', 0)
      >>> for _ in range(9):
      ...     crc = zlib.crc32(bytes[0], crc)
      >>> crc + 2**32
      3136421207
      

      注意,不要在循环中使用i 变量。

      【讨论】:

        【解决方案4】:

        这是因为CRC32是按位计算的。

        您在 C(数据大小为 9 个字节)和 python 中分别计算每个数字的 CRC(可能只需要 4 或 8 个字节来表示)。

        字节数可能不同,会导致不同的CRC。

        尝试用C计算123456789的CRC。

        编辑:关于str(i),编码可能不同,而且它是ASCII值。由于 1 和 '1' 不同,您将不会得到相同的 CRC。试试

        crc = zlib.crc32(int(str(i)), crc) # or simply i
        

        在 C 代码中,数字只有 4 个字节,而在 python 中,它是字符串。 32 位整数和数组会给出不同的结果。

        请注意,对于位级别的相同表示(具有相同位数),您将获得相同的 CRC。即使一位不同或额外或更少,您也会得到完全不同的 CRC。

        【讨论】:

        • 我想我明白你的意思,但我不确定它对我有帮助。查看我的编辑。
        • 使用 TypeError: must be string or read-only buffer, not int 失败
        • 它表示只读缓冲区。这意味着您可以将您的号码存储在 4 字节缓冲区中并尝试。
        猜你喜欢
        • 2015-03-19
        • 1970-01-01
        • 1970-01-01
        • 2012-01-11
        • 2020-05-14
        • 2021-11-02
        • 1970-01-01
        • 2016-09-19
        • 1970-01-01
        相关资源
        最近更新 更多