代码之家  ›  专栏  ›  技术社区  ›  sokol

如何使crc32的结果与cksum匹配?

  •  1
  • sokol  · 技术社区  · 2 年前

    我有代码,必须将0x3B9ACA02432543更改为某个值,使此代码的结果等于cksum结果。

    我试图将其更改为cksum默认值0x04C11DB7,但结果值不同

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            exit(EXIT_FAILURE);
        } else {
            FILE *f = NULL;
            int c;
    
            f = fopen(argv[1], "rb");
            if (f == NULL)
                perror("fopen()");
            else {
                int size = 0;
                int crc;
                int c;
                int i, j;
                int crc_table[256];
                for (i = 0; i < 256; i++) {
                    crc = i;
                    for (j = 0; j < 8; j++)
                        crc = crc & 1 ? (crc >> 1) ^ 0x3B9ACA02432543 : crc >> 1;
    
                    crc_table[i] = crc;
                }
                crc = 0;
    
                while ((c = fgetc(f)) != EOF) {
                    ++size;
                    crc = crc_table[(crc ^ c) & 0xFF] ^ (crc >> 8);
                }
                crc ^= 0xFFFFFFFFUL;
                printf("%u\n", crc);
            }
    
        }
    
        return 0;
    
    }
    
    2 回复  |  直到 2 年前
        1
  •  4
  •   Mark Adler    2 年前

    您没有说明什么操作系统或源 cksum 您正在使用。不同系统的情况不同。在我的macOS(BSD派生)系统上, cksum -o 3 将计算您可能参考的标准CRC-32。

    在这种情况下,您需要将初始CRC设置为 0xffffffff ,需要使用多项式的反射, 0x04c11db7 ,即 0xedb88320 。此外,您应该使用长度至少为32位的类型。 long int 不是。您还需要对CRC计算使用无符号类型,这样向下移位就不会复制高位。

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        else {
            FILE *f = NULL;
            f = fopen(argv[1], "rb");
            if (f == NULL)
                perror("fopen()");
            else {
                unsigned long crc;
                int c;
                int i, j;
                unsigned long crc_table[256];
                for (i = 0; i < 256; i++) {
                    crc = i;
                    for (j = 0; j < 8; j++)
                        crc = crc & 1 ? (crc >> 1) ^ 0xedb88320 : crc >> 1;
                    crc_table[i] = crc;
                }
                crc = 0xffffffff;
                while ((c = fgetc(f)) != EOF)
                    crc = crc_table[(crc ^ c) & 0xff] ^ (crc >> 8);
                crc ^= 0xffffffff;
                printf("%lu\n", crc);
            }
        }
        return 0;
    }
    

    这个 POSIX cksum 是另一种变体。它使用非反射CRC,从 0 而不是 0xffffffff ,并将数据的长度附加到用于CRC计算的数据。该长度按小端序排列,表示长度所需的字节数最少。为了方便起见,我使用了C99提供的显式大小的整数:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        else {
            FILE *f = NULL;
            f = fopen(argv[1], "rb");
            if (f == NULL)
                perror("fopen()");
            else {
                uint32_t crc;
                uint32_t crc_table[256];
                for (uint32_t i = 0; i < 256; i++) {
                    crc = i << 24;
                    for (int j = 0; j < 8; j++)
                        crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
                    crc_table[i] = crc;
                }
                uint64_t size = 0;
                crc = 0;
                int c;
                while ((c = fgetc(f)) != EOF) {
                    size++;
                    crc = crc_table[(crc >> 24) ^ c] ^ (crc << 8);
                }
                while (size) {
                    crc = crc_table[(crc >> 24) ^ (size & 0xff)] ^ (crc << 8);
                    size >>= 8;
                }
                crc = ~crc;
                printf("%lu\n", (unsigned long)crc);
            }
        }
        return 0;
    }
    
        2
  •  3
  •   ЯДPTГФИ    2 年前

    要使代码与 cksum 实用程序,您需要使用与 cksum 使用。这个 cksum 该实用程序通常使用多项式为 0x04C11DB7 。以下是代码中需要解决的一些问题:

    多项式 0x3B9ACA02432543 对于32位CRC来说太大。多项式应该是32位的值,通常 0x04C11DB7 对于 cksum

    您需要初始化 crc 0xFFFFFFFFUL 在计算开始时。

    对于典型的CRC32计算,表初始化和计算算法似乎不正确。

    这就是你可以做的:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            exit(EXIT_FAILURE);
        } else {
            FILE *f = NULL;
            int c;
    
            f = fopen(argv[1], "rb");
            if (f == NULL)
                perror("fopen()");
            else {
                unsigned int crc;
                unsigned int crc_table[256];
                unsigned int poly = 0x04C11DB7;  // Polynomial for cksum
                unsigned int temp_crc;
    
                // Build CRC table
                for (int i = 0; i < 256; i++) {
                    temp_crc = i << 24;
                    for (int j = 0; j < 8; j++) {
                        if (temp_crc & 0x80000000)
                            temp_crc = (temp_crc << 1) ^ poly;
                        else
                            temp_crc <<= 1;
                    }
                    crc_table[i] = temp_crc;
                }
    
                crc = 0xFFFFFFFF;  // Initialize CRC
    
                while ((c = fgetc(f)) != EOF) {
                    crc = (crc << 8) ^ crc_table[((crc >> 24) ^ c) & 0xFF];
                }
    
                crc = ~crc;  // Finalize CRC
                printf("%u\n", crc);
            }
        }
    
        return 0;
    }