每次程序更改的 CRC 值为 运行

Value of CRC changing everytime program is run

我正在用 C 编写一个 CLI 实用程序,用于分析 PNG 文件并输出有关它的数据。更具体地说,它打印出 PNG 文件中每个块的长度、CRC 和类型值。我正在为 PNG 文件格式使用 official specification,它说每个块都有一个编码的 CRC 值以确保数据完整性。

我的工具 运行ning 很好,它输出正确的长度和类型值,并输出 看起来 的 CRC 正确值(如它被格式化为 4 字节十六进制) - 唯一的问题是每次我 运行 这个程序时,CRC 的值都会改变。这是否正常,如果不是,可能是什么原因造成的?

这是代码的主要部分

CHUNK chunk;
BYTE buffer;
int i = 1;

while (chunk.type != 1145980233) {  // 1145980233 is a magic number that signals our program that IEND chunk 
                                        // has been reached it is just the decimal equivalent of 'IEND'
        
        printf("============\nCHUNK: %i\n", i);
        // Read LENGTH value; we have to buffer and then append to length hexdigit-by-hexdigit to account for 
        // reversals of byte-order when reading infile (im not sure why this reversal only happens here)
        for(unsigned j = 0; j < 4; ++j) {
            fread(&buffer, 1, sizeof(BYTE), png);
            chunk.length = (chunk.length | buffer)<<8;  // If length is 0b4e and buffer is 67 this makes sure that length
                                                        // ends up 0b4e67 and not 0b67
        }
        chunk.length = chunk.length>>8; // Above bitshifting ends up adding an extra 00 to end of length
                                        // This gets rid of that
        printf("LENGTH: %u\n", chunk.length);

        // Read TYPE value
        fread(&chunk.type, 4, sizeof(BYTE), png);
        // Print out TYPE in chars
        printf("TYPE: ");
        printf("%c%c%c%c\n", chunk.type & 0xff, (chunk.type & 0xff00)>>8, (chunk.type & 0xff0000)>>16, (chunk.type & 0xff000000)>>24);
        
        // Allocate LENGTH bytes of memory for data
        chunk.data = calloc(chunk.length, sizeof(BYTE));
        // Populate DATA
        for(unsigned j = 0; j < chunk.length; ++j) {
            fread(&buffer, 1, sizeof(BYTE), png);
        }

        // Read CRC value
        for(unsigned j = 0; j < 4; ++j) {
            fread(&chunk.crc, 1, sizeof(BYTE), png);
        }
        printf("CRC: %x\n", chunk.crc);
        printf("\n");
        i++;
    }

这里有一些预处理器指令和全局变量

#define BYTE uint8_t

typedef struct {
    uint32_t length;
    uint32_t type;
    uint32_t crc;
    BYTE* data;
} CHUNK;

这是我得到的一些输出示例

运行 1 -

============
CHUNK: 1
LENGTH: 13
TYPE: IHDR
CRC: 17a6a400

============
CHUNK: 2
LENGTH: 2341
TYPE: iCCP
CRC: 17a6a41e

运行 2 -

============
CHUNK: 1
LENGTH: 13
TYPE: IHDR
CRC: 35954400

============
CHUNK: 2
LENGTH: 2341
TYPE: iCCP
CRC: 3595441e

运行 3 -

============
CHUNK: 1
LENGTH: 13
TYPE: IHDR
CRC: 214b0400

============
CHUNK: 2
LENGTH: 2341
TYPE: iCCP
CRC: 214b041e

如您所见,CRC 值每次都不同,但在每个 运行 中它们都非常相似,而我的直觉告诉我情况不应该如此,CRC 值不应该改变.

为了确认一下,我也运行

    $ cat test.png > file1
    $ cat test.png > file2
    $ diff -s file1 file2
    Files file1 and file2 are identical

因此两次访问文件不会像预期的那样更改其中的 CRC 值。

谢谢,

这个:

fread(&chunk.crc, 1, sizeof(BYTE), png);

不断用从文件中读取的字节覆盖 chunk.crc 的第一个字节。 chunk.crc 的其他三个字节永远不会被写入,因此当您的程序启动时,您会在这些位置看到内存中随机出现的内容。您会注意到末尾的 001e 是一致的,因为这是正在写入的一个字节。

在你的数据读取循环中也有同样的问题:

fread(&buffer, 1, sizeof(BYTE), png);

一个不相关的错误是您正在以 32 位整数的形式累积字节:

chunk.length = (chunk.length | buffer)<<8;

然后在该循​​环结束后,将其回滚:

chunk.length = chunk.length>>8;

这将始终丢弃长度的最高有效字节,因为您将它推到 32 位的顶部,然后将八个零位回滚到它的位置。相反,您需要这样做:

chunk.length = (chunk.length << 8) | buffer;

然后32位全部保留,最后不用修了

这是个坏主意:

fread(&chunk.type, 4, sizeof(BYTE), png);

因为它不便携。您在 chunk.type 中的最终结果取决于它 运行 所在的体系结构的字节顺序。对于“IHDR”,您将在小端机器上获得 0x52444849,在大端机器上获得 0x49484452