[英]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.