【发布时间】:2018-05-08 03:56:37
【问题描述】:
我目前正在尝试读取一个 PNG 文件,一次一个字节,当我使用 fread((void*), size_t, size_t, FILE*) 和 fgetc(FILE*) 时,我得到了不同的结果。
我本质上想“一次读取一个字节,直到文件结束”,我以两种不同的方式这样做。在这两种情况下,我都通过以下方式以二进制模式打开我想要的图像:
FILE* input = fopen( /* Name of File */, 'rb');
并将每个字节存储在一个字符中,char c
fread:while( fread(&c, 1, 1, input) != 0) //read until there are no more bytes read
fgetc:
while( (c = fgetc(input)) != EOF) //Read while EOF hasn't been reached
在fread 的情况下,我读取了我需要做的所有字节。读取功能在文件末尾停止,我最终打印了所有 380,000 个字节(这是有道理的,因为输入文件是 380kB 文件)。
但是,在fgetc 的情况下,一旦我到达一个值为ff 的字节(即-1,宏EOF 的值),我就会停止。
我的问题是,如果两个函数都在做同样的事情,一次读取一个字节,那么 fread 怎么知道继续读取,即使它遇到了一个值为EOF 的字节?在此基础上,如果在读取文件时传递了EOF,fread 如何知道何时停止?
【问题讨论】:
-
EOF的 int 值为-1,而不是char值。通常,EOF根本不是合法的字节值。如果将其存储到char,当然,您无法区分,但这就是为什么fgetc返回int,而不是char,因为0xff是一个完全合法的返回值 不 表示EOF。 -
你的结论基于一个错误的前提,即“
ff(即-1,宏EOF的值”是错误的。这是c的类型导致了这种混乱。将c的类型更改为int,问题就会消失。谷歌类似“为什么fgetc()返回int而不是char?”。 -
@ShadowRanger 好的。这更有意义......我现在理解它的方式是:
EOF的类型为INT,即 4 个字节。EOF的值为 -1,这意味着四个连续字节的模式为“0xff。因此,因为在 fgetc 场景中,我只读取了 1 个0xff,并将EOF字节截断为 1字节,我欺骗程序(错误地)提前完成......这是对问题的合理解释吗? -
@ricardo:不。文件系统知道 fike 有多长,因为它在文件元数据中保留了长度。它不会在文件数据之后放置任何类型的标记值。如果您尝试读取文件并且读取指针位于文件末尾,则将设置
FILE结构中的 eof 标志,并且将从您用于读取文件的任何库函数返回 EOF 指示。在fgetc的情况下,EOF 返回值为负数,不能与字符代码混淆,因为fgetc始终返回非负字符代码,即使char是有符号类型。 -
...这就是为什么
fgetc返回int而不是char。fgetc的许多可能返回值不能表示为(有符号的)char。将这样的值存储在(有符号的)char中是未定义的行为,尽管 gcc 可靠地符号扩展了返回值的最后 8 位。 (在大多数架构中,“符号扩展”是一种奇特的说法,即“只是假装第 8 位是符号”,但理论上char类型有可能超过 8 位。)