2015-01-20 2 views
0

Im экспериментирует с crc32 в Python и C, но мои результаты не совпадают.C zlib crc32 и Python zlib 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 

В питоне я добавляю с 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

Там были проблемы в вашем оригинальном C и фрагменты кода на Python. Что касается второго фрагмента C, я не пытался его скомпилировать, но он не переносится, поскольку порядок байтов внутри int зависит от платформы. Таким образом, он будет давать разные результаты в зависимости от endianness процессора.

Одна проблема, как упомянула Серж Баллеста, это разница между {1, 2, 3, 4, 5, 6, 7, 8, 9} и {'1', '2', '3', '4', '5', '6', '7', '8', '9'}. Другая проблема заключается в том, что цикл в вашем исходном коде C фактически не просматривал данные, так как вы не использовали i в цикле, как упоминал бав.

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.

+0

Отличный ответ, спасибо. Я был почти там, собрав части из других ответов, но это было золотым. – evading

+0

Спасибо! См. Мое обновление для альтернативного способа обработки неподписанного типа int Python. –

0

Это потому, что CRC32 вычисляется на уровне бит.

Вы вычисляете CRC для каждой цифры индивидуально в C (размер данных составляет 9 байтов) и в python для целого числа (для представления всего 4 или 8 байтов).

Количество байтов может быть разным и приведет к разным CRC.

Попробуйте вычислить CRC из 123456789 в С.

Edit: Что касается str(i), кодирование может быть различным и, кроме того, это значение ASCII. Поскольку 1 и 1 не являются одинаковыми, вы не получите тот же CRC. Попробуйте

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

В коде C число составляет всего 4 байта, тогда как в python это строка. 32-битное целое число и массив будут давать разные результаты.

Обратите внимание, что для того же представления на уровне бит (с таким же количеством бит) вы получите тот же CRC. Даже если один бит отличается или лишний или меньше, вы получите совсем другой CRC.

+0

Я думаю, что понимаю, что вы имеете в виду, но я не уверен, что это помогает мне. См. Мое редактирование. – evading

+0

@evading: См. Редактирование. – doptimusprime

+0

Ошибка с 'TypeError: должен быть строковым или только для чтения, а не int' – evading

1

Точная копия первого с-сниппета дает тот же результат:

>>> 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 переменную в цикле.

1

В соответствии с www.lammertbies.nl что подробные ссылки на вычисления CRC и подпрограмм C, то CRC32 из ASCII строки 123456789 в 0xCBF43926, то есть 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); 

В качестве альтернативы, если то, что вы хотите, действительно CRC 32 для uint8_t bytes[NUM_BYTES] = {1, 2, 3, 4, 5, 6, 7, 8, 9};, вы должны использовать в Python 2 ,х:

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

выходы: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t'

затем

zlib.crc32(s) 

выходы: 1164760902

Nota: В Python 3.x, вы бы написали: s = bytes(range(10))