Language
C
Compiler
gcc 13.2.0
Options
Warnings
Compiler Default
no pedantic
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
uint32_t crc32_inv_shift(uint32_t status_after) {
static uint32_t table[256], table_ready = 0;
if (!table_ready) {
static const uint32_t MAGIC = UINT32_C(0xEDB88320);
for (int b = 0; b < 256; b++) {
uint32_t status = (uint32_t)b << 24;
for (int i = 0; i < 8; i++) {
uint32_t msb = status & UINT32_C(0x80000000);
if (msb) {
status ^= MAGIC;
status <<= 1;
status |= 1;
} else {
status <<= 1;
}
}
table[b] = status;
}
table_ready = 1;
}
return table[status_after >> 24] ^ (status_after << 8);
}
uint32_t crc32_inv(uint32_t status_after, uint8_t byte_value) {
return crc32_inv_shift(status_after) ^ byte_value;
}
// 成功時1、失敗時0を返す
int crc32_bytes(uint8_t bytes_out[], int num_bytes, uint32_t status_before, uint32_t status_after) {
uint32_t status = status_after;
if (num_bytes < 0 || 4 < num_bytes) return 0;
if (num_bytes == 0) return status_before == status_after;
// シフトとマジックナンバーのXORの処理を逆回しする
for (int i = 0; i < num_bytes; i++) {
status = crc32_inv_shift(status);
}
// 更新前の状態をXORする
status ^= status_before;
// 上位が0になっていることを確認する
if (num_bytes < 4 && (status & (UINT32_C(0xFFFFFFFF) << 8 * num_bytes))) return 0;
// バイト列を取り出す
for (int i = 0; i < num_bytes; i++) {
bytes_out[i] = status >> 8 * i;
}
return 1;
}
void test(uint32_t status_before, uint32_t status_after) {
printf("0x%08" PRIx32 " -> 0x%08" PRIx32 "\n", status_before, status_after);
for (int size = 1; size <= 4; size++) {
uint8_t data[4];
if (crc32_bytes(data, size, status_before, status_after)) {
for (int i = 0; i < size; i++) {
if (i > 0) putchar(' ');
printf("%02x", (unsigned int)data[i]);
}
putchar('\n');
}
}
}
int main(void) {
const char *data = "IEND";
uint32_t status = UINT32_C(0xAE426082);
printf("CRC32: 0x%08" PRIx32 "\n", status);
status = ~status; // 最後に行ったビット反転を打ち消す
for (int i = (int)strlen(data) - 1; i >= 0; i--) {
printf("after data[%d] = 0x%02x : 0x%08" PRIx32 "\n", i, data[i], status);
status = crc32_inv(status, data[i]);
}
printf("initial value: 0x%08" PRIx32 "\n", status);
putchar('\n');
test(UINT32_C(0x992BAC53), UINT32_C(0x639F4775));
test(UINT32_C(0x992BAC53), UINT32_C(0x51BD9F7D));
test(UINT32_C(0x22FDE946), UINT32_C(0x51BD9F7D));
test(UINT32_C(0xFFFFFFFF), UINT32_C(0x51BD9F7D));
return 0;
}
$ gcc prog.c -Wall -Wextra
CRC32: 0xae426082
after data[3] = 0x44 : 0x51bd9f7d
after data[2] = 0x4e : 0x639f4775
after data[1] = 0x45 : 0x992bac53
after data[0] = 0x49 : 0x22fde946
initial value: 0xffffffff
0x992bac53 -> 0x639f4775
4e
8a 6a fb 27
0x992bac53 -> 0x51bd9f7d
4e 44
e5 16 9a 22
0x22fde946 -> 0x51bd9f7d
45 4e 44
f0 53 4c 99
0xffffffff -> 0x51bd9f7d
49 45 4e 44
Exit Code:
0