为什么 fread() 给出看似随机的数据?

Why does fread() give seemingly random data?

我有以下 C 代码,它以 rb+ 模式打开一个文件,然后写入 100 个字节的值 0。当我读取偏移量不是 0 的文件时,我得到 96。这是为什么?

FILE *fp = fopen("myfile", "rb+");
rewind(fp);
char zero = 0;
fwrite(&zero, 1, 100, fp);
char result;
fseek(fp, 1, SEEK_SET);
fread(&result, 1, 1, fp);
printf("%d\n", result);

我在 Linux x64 上使用 GCC。

你可能想要这样的东西:

int i; for (i=0;i<100;++i){fwrite(&zero, 1, 1, fp);}

不能从指向单个字符的指针写入 100 个字节。

根据您在评论中的说明,您的意图是向文件写入 100 个零字节。至少有两种甚至三种方法可以做到这一点。

首先是分配一个100个零初始化字节的数组,写成:

char zeroes[100] = { 0 };
fwrite(zeroes, sizeof(char) /* == 1 */, sizeof(zeroes), f);

如果您想写入 10,000 或 10,000,000 个零字节,这就无法很好地扩展。你也可以这样做:

char zero = 0;
for (int i = 0; i < 100; ++i) fwrite(&zero, sizeof(char), 1, f);

这可以更好地扩展,但性能很差,因为执行单个大写操作总是比执行许多小写操作更有效。相反,您可以查找文件中的较后位置,然后只写入最后一个字节。 On POSIX systems, this is guaranteed 用零填充文件较早未写入的部分:

char zero = 0;
fseek(f, 99, SEEK_SET);
fwrite(&zero, sizeof(char) /* == 1 */, 1, f);

相信 Windows' MSVCRT 运行时也提供零填充保证,但我无法立即在 MSDN 上找到证明(这可能提出一个很好的问题)。如果有人知道 Windows,其他平台,and/or C 标准本身的某些版本是否做出或不做出此保证,则可以改进此答案。

当然,如果您在POSIX系统上并且不需要可移植代码,您可以使用ftruncate() which makes the same guarantee without even needing to do an fwrite(). Windows has SetEndOfFile()但是该函数用未定义值而不是零字节填充文件的扩展部分。