微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

每次程序运行时CRC的值都会改变

如何解决每次程序运行时CRC的值都会改变

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

我的工具运行良好,它输出正确的长度和类型值,并输出看起来是 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,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,png);
        }

        // Read CRC value
        for(unsigned j = 0; j < 4; ++j) {
            fread(&chunk.crc,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,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,png);

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。