咨询:逐字节读取PNG文件时fread与fgetc的结果差异
为什么
fread和fgetc逐字节读取PNG文件结果不同? 这个问题的核心差异其实来自**char类型的符号特性**和两个函数的返回值/存储逻辑区别,我来一步步拆解清楚:
1. char的符号性是头号元凶
你把读取到的字节存在char变量里,这是最关键的问题。C标准里char可以是有符号或无符号类型(取决于你的编译器):
- 如果是有符号
char,当读取到PNG文件中值为0x80(十进制128)到0xFF(255)的字节时,这些字节会被解释为负数(比如0xFF会变成-1)。 - 而
fgetc的返回值是int类型,它会先把读取的字节转换成unsigned char,再提升到int,所以正常读取的字节值范围是0到255;只有遇到文件结束或读取错误时,才会返回EOF(通常定义为-1)。
举个具体的例子:当读取PNG里的0xFF字节时:
- 用
fread读到char c中,如果char是有符号的,c的值会是-1; - 用
fgetc读到int ch中,ch的值是255;
这直接就造成了两者结果的差异。
2. 错误/文件结束的处理逻辑不同
fread返回的是成功读取的字节数:当遇到文件结束或者读取错误时,返回0。但它不会区分到底是文件读完了还是读出错了,需要你额外用feof()或ferror()来判断。fgetc返回EOF表示文件结束或错误:同样需要用feof()/ferror()区分,但它的返回值是int,不会把正常的字节值和EOF搞混——因为正常字节是0-255,EOF是-1,两者完全不重叠。
3. 让两种方式结果一致的解决方案
要消除差异,你只需要调整存储字节的变量类型,或者处理逻辑:
方案一:改用unsigned char存储字节
把存储变量改成无符号类型,确保所有字节都被正确解析为0-255的数值:
unsigned char c; FILE* input = fopen("your_file.png", "rb"); while (fread(&c, 1, 1, input) != 0) { // 这里c的值和fgetc返回的int值(截断后)完全一致 // 处理字节c } fclose(input);
方案二:用int存储(对齐fgetc的逻辑)
如果你习惯用int来存储,也可以像fgetc那样先读入无符号字符再转成int:
int c; unsigned char temp; FILE* input = fopen("your_file.png", "rb"); while (fread(&temp, 1, 1, input) != 0) { c = temp; // 此时c的范围是0-255,和fgetc的返回值一致 // 处理c } fclose(input);
另外补充一下fgetc的正确写法:必须用int存储返回值,否则如果char是有符号的,读到0xFF时会被误判为EOF,导致循环提前终止:
int ch; FILE* input = fopen("your_file.png", "rb"); while ((ch = fgetc(input)) != EOF) { unsigned char c = (unsigned char)ch; // 处理字节c } fclose(input);
内容的提问来源于stack exchange,提问作者Ricardo Iglesias
相关产品推荐
相关产品推荐

