繁体   English   中英

CRC32 - 使用 TABLE 算法和 04C11DB7 多项式的错误校验和

[英]CRC32 - wrong checksum using TABLE algorithm and 04C11DB7 polynomial

我正在遵循代码校正算法的无痛指南。 https://zlib.net/crc_v3.txt )我已经设法编写了一个 TABLE 算法,对增强部分使用了额外的循环(我希望如此)。 我正在尝试编写一个使用最广泛的 CRC32 版本(带有 0x04C11DB7 多项式),但我无法获得正确的 CRC 值。

我已经用提到的多项式获得了正确的 CRC32 值表。 我生成 CRC32 的代码(第 9 章和第 10 章):

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define CRC32_BYTE_POSSIBLE_VALUES 255
#define CRC32_LAST_BIT_MASK 0x80000000

#define CRC32_POLYNOMIAL 0x04C11DB7

uint32_t __crc32_table[CRC32_BYTE_POSSIBLE_VALUES] = { 0 };

void __crc32_fill_crc_table() {
    uint32_t reg;
    uint8_t byte = 0;

    for (;;) {
        reg = (byte << 24);

        for (uint8_t byte_size = 0; byte_size < 8; byte_size++) {
            if (reg & CRC32_LAST_BIT_MASK) {
                reg <<= 1;
                reg ^= CRC32_POLYNOMIAL;
            } else {
                reg <<= 1;
            }
        }

        __crc32_table[byte] = reg;
        if (byte == 255)
            break;
        else
            byte++;
    }

}

void __crc32_print_table(uint32_t *arr) {
    printf(" 0x%08X ", arr[0]);

    for (uint32_t i = 1; i < 256; i++) {
        if (!(i % 8))
            printf("\n");

        printf(" 0x%08X ", arr[i]);

    }

    printf("\n");
}

uint8_t inverse_byte(uint8_t byte) {
    uint8_t reflected_byte = 0;

    for (uint8_t i = 0; i < 8; i++) {
        if (byte & (1 << i))
            reflected_byte |= (1 << (7 - i));
    }

    return reflected_byte;
}

uint32_t inverse(uint32_t src) {

    uint32_t toret;

    for (uint8_t i = 0; i < 32; i++) {
        if (src & (1 << i))
            toret |= (1 << (31 - i));
    }

    return toret;
}


uint32_t __crc32_table_approach( unsigned char *data, size_t size) {
    uint32_t reg = -1;
    uint8_t top_byte;

    for (size_t i = 0; i < size; i++) {
        top_byte = (uint8_t)(reg >> 24);
        reg = (reg << 8) | inverse_byte(data[i]);
        reg ^= __crc32_table[top_byte];
    }

    for (size_t i = 0; i < 4; i++) {
        top_byte = (uint8_t) (reg >> 24);
        reg = (reg << 8) ;
        reg ^= __crc32_table[top_byte];
    }

    return inverse(reg) ^ -1;
}

uint32_t calc_crc32(unsigned char *data, size_t size) {
    if (!__crc32_table[1])
        __crc32_fill_crc_table();

    __crc32_print_table(__crc32_table);

    return __crc32_table_approach(data, size);
}


int main( int argc, char** argv )
{
    
    unsigned char* test = "123456789";
    size_t test_len = strlen(test);

    uint32_t crc = calc_crc32(test, test_len);
    printf("CRC32: 0x%08X", crc);
    return 0;
}

逆 function 反转 UINT32 值的位,并且 function inverse_byte 反转 UINT8 值的位。

但是对于 '123456789' 字符串,我得到了错误的校验和。 有人可以帮助我吗? 或者给点建议?


输入字符串:'123456789'

输出的CRC:CRC32:0x22016B0A

所需的 CRC:CRC32:0xCBF43926

你让你的数组一个字太短了。 它需要是:

#define CRC32_BYTE_POSSIBLE_VALUES 256

虽然那部分可能仍然有效,因为 C。

您需要初始化要反转的变量:

    uint32_t toret = 0;

这些行:

    top_byte = (uint8_t)(reg >> 24);
    reg = (reg << 8) | inverse_byte(data[i]);

需要:

    top_byte = (uint8_t)(reg >> 24) ^ inverse_byte(data[i]);
    reg <<= 8;

你需要删除这些行:

 for (size_t i = 0; i < 4; i++) { top_byte = (uint8_t) (reg >> 24); reg = (reg << 8); reg ^= __crc32_table[top_byte]; }

然后你会得到正确的答案。

然而,反转每个输入字节是浪费时间。 相反,您可以反转计算和多项式。 请参阅 rcgldr 的答案。

使用右移 CRC 的示例代码(0xedb88320 是 0x04C11DB7 的反映版本):

#include <iostream>
#include <iomanip>

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

uint32_t crctbl[256];

void gentbl(void)
{
uint32_t crc;
uint32_t c;
uint32_t i;
    for(c = 0; c < 0x100; c++){
        crc = c;
        for(i = 0; i < 8; i++){
            crc = (crc & 1) ? (crc >> 1) ^ 0xedb88320 : (crc >> 1);
        }
        crctbl[c] = crc;
    }
}

uint32_t crc32(uint8_t * bfr, size_t size)
{
uint32_t crc = 0xfffffffful;
    while(size--)
        crc = (crc >> 8) ^ crctbl[(crc & 0xff) ^ *bfr++];
    return(crc ^ 0xfffffffful);
}

int main(int argc, char**argv)
{
uint32_t crc;
uint8_t msg[10] = "123456789";

    gentbl();
    crc = crc32(msg, 9);
    std::cout << "crc " << std::hex << std::setw(8) << std::setfill('0') << crc << std::endl;
    return(0);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM