C文件校验和

8

如何使用C语言制作文件的校验和?我不想使用第三方库,只使用默认的C语言,并且速度非常重要(尽管文件大小小于50MB)。

谢谢!


你对特定的校验和/哈希算法感兴趣吗? - Michael Burr
如果测试通过,只需将“true”分配给布尔值即可。 - Checksummmmm
任何校验和都比磁盘I/O快得多,所以这并不重要。你需要决定你想要什么。如果你想要一个加密哈希,那就有点不同于CRC32或Murmur。 - Steven Sudit
5个回答

17

我建议先从简单的开始,如果后面出现问题才考虑引入快速需求。

太多时间被浪费在解决不存在的问题上(参见YAGNI)。

所谓简单,是指仅需将校验和字符(这里所有的字符都是无符号的)初始化为零,并读入每个字符并将其从校验和字符中减去,直到达到文件末尾,假设你的实现具备智能包装功能。

类似于以下程序:

#include <stdio.h>

unsigned char checksum (unsigned char *ptr, size_t sz) {
    unsigned char chk = 0;
    while (sz-- != 0)
        chk -= *ptr++;
    return chk;
}

int main(int argc, char* argv[])
{
    unsigned char x[] = "Hello_";
    unsigned char y = checksum (x, 5);
    printf ("Checksum is 0x%02x\n", y);
    x[5] = y;
    y = checksum (x, 6);
    printf ("Checksum test is 0x%02x\n", y);
    return 0;
}

输出结果为:

Checksum is 0x0c
Checksum test is 0x00
那个checksum函数实际上可以完成两种任务。如果你传递给它一个没有校验和的数据块,它会返回该数据块的校验和。如果你传递给它一个带有校验和的数据块,它将返回零以表示正确的校验和,或返回非零值以表示错误的校验和。
这是最简单的方法,可以检测大多数随机错误。但它不能检测像交换了两个字符这样的边界情况,所以如果你需要更高的准确性,可以使用像FletcherAdler这样的东西。
这两个维基页面都有示例C代码,你可以直接使用,或者分析并重新编写以避免IP问题(如果你担心的话)。

-1 还有许多更好的哈希函数,但仍然很简单。http://www.cse.yorku.ca/~oz/hash.html - u0b34a0f6ae
2
@Kaizer,这与简单性无关。您提供的链接中的那些函数是哈希函数,它们的目的与校验和完全不同——它们的意图是最大化桶之间的键分布平衡,而不仅仅是获取文件“值”的指示以进行检查(虽然它们可以用于此,但在这种情况下它们没有任何好处)。此外,它们都执行比简单加法更复杂的操作,并且引用问题时,“速度非常重要”。 - paxdiablo
简单地将所有字符相加是最简单的校验和,但它不能防止任何交换,比如 "Holle_". - u0b34a0f6ae
2
@Kaizer,我不确定你所说的“交换”是什么意思,但我假设你指的是文件中某处交换了字符。但是_任何_校验和(或哈希)都容易受到无法检测的输入值错误的影响。这是它们的本质,因为它们涉及信息的丢失。如果您使输出值更依赖于位置(例如使用djb2),则可以提高捕获某些问题的可能性,但这会引入额外的计算,从而减慢过程。正是对速度的强调使我集中精力研究简单的解决方案。 - paxdiablo
然而,我不是来为自己辩护的,你已经做出了决定,我能做的只是解释为什么我认为你错了 :-) 我不想在评论系统中再加入更多的解释,所以就到这里吧。 - paxdiablo

9
  1. 确定您想要使用的算法(CRC32是一个例子)
  2. 在维基百科或其他来源上查找该算法
  3. 编写代码来实现该算法
  4. 如果代码未能正确实现算法,请在此处发布问题
  5. 获得利润?

2
简单快速
FILE *fp = fopen("yourfile","rb");
unsigned char checksum = 0;
while (!feof(fp) && !ferror(fp)) {
   checksum ^= fgetc(fp);
}

fclose(fp)

非常错误。首先:为什么“while(!feof(file))”总是错误的?第二:fgetc()返回int而不是char,因为EOF是一个负的int值,不能表示为char。这段代码将包括从fgetc()返回的额外的EOF并在“校验和”中截断为char值。 - Andrew Henle

2

通常情况下,使用好的多项式的CRC32可能是非加密哈希校验和的最佳选择。点击这里查看一些原因:http://guru.multimedia.cx/crc32-vs-adler32/在右侧单击纠错类别以获取更多与crc相关的文章。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接