C zlib crc32 和 Python zlib crc32 不匹配。

3

我在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 值为: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);
}

仍然没有获得相同的结果。

4个回答

6

您原始的C和Python代码片段存在问题。至于您的第二个C片段,我没有尝试编译它,但它不具有可移植性,因为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

查看此主题的更多信息,请参见此处的答案:如何在Python中将有符号整数转换为无符号整数


非常好的答案,谢谢。我几乎通过拼凑其他答案的部分就快要解决了,但这个答案真是太棒了。 - evading
谢谢!请看我的更新,关于处理Python缺乏无符号整数类型的另一种方法。 - PM 2Ring
1
gcc -std=c99 -lz -o crctest test.c 出现了 undefined references 错误,应该改为 gcc -std=c99 -o crctest test.c -lz - rkta

2
根据具有CRC计算和C例程详细参考的网站www.lammertbies.nl,ASCII字符串123456789的CRC32为0xCBF43926,即无符号32位整数以十进制形式表示为3421780262
这意味着您的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))


1
您的第一个 c-snippet 的精确副本将给出相同的结果:
>>> 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 变量。

0

这是因为CRC32是以位级别计算的。

在C语言中,你是对每个数字单独计算CRC(数据大小为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。

我觉得我理解你的意思,但不确定它是否对我有帮助。请看我的修改。 - evading
出现TypeError: must be string or read-only buffer, not int错误。 - evading
只读缓冲区。这意味着你可以将你的数字存储在4字节缓冲区中并尝试。 - doptimusprime

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