C zlib crc32 和 Python zlib crc32 不匹配
C zlib crc32 and Python zlib crc32 doesn't match
我在 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 中,我将 with 2**32 添加到 "cast" 到 unsigned int。
我在这里错过了什么?
[编辑 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);
}
结果还是不一样。
因为CRC32是按位计算的
您在 C 语言(数据大小为 9 字节)和 python 中为整数(可能只需要 4 或 8 个字节来表示)分别计算每个数字的 CRC。
字节数可能不同,会导致不同的 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。
您的第一个 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
变量。
根据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,你必须使用 in 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))
您的原始 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
有关此主题的更多信息,请参阅此处的答案:How to convert signed to unsigned integer in python。
我在 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 中,我将 with 2**32 添加到 "cast" 到 unsigned int。
我在这里错过了什么?
[编辑 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);
}
结果还是不一样。
因为CRC32是按位计算的
您在 C 语言(数据大小为 9 字节)和 python 中为整数(可能只需要 4 或 8 个字节来表示)分别计算每个数字的 CRC。
字节数可能不同,会导致不同的 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。
您的第一个 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
变量。
根据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,你必须使用 in 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))
您的原始 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
有关此主题的更多信息,请参阅此处的答案:How to convert signed to unsigned integer in python。