使用fgetc时是否可能将EOF与正常字节值混淆?
我们经常这样使用使用fgetc时是否可能将EOF与正常字节值混淆?,c,language-lawyer,binaryfiles,fgetc,C,Language Lawyer,Binaryfiles,Fgetc,我们经常这样使用fgetc: int c; while ((c = fgetc(file)) != EOF) { // do stuff } 从理论上讲,如果文件中的某个字节的值为EOF,则该代码存在错误-它将提前中断循环并无法处理整个文件。这种情况可能吗 据我所知,fgetc在内部将从文件读取的字节强制转换为无符号字符,然后转换为int,并返回它。如果int的范围大于无符号字符的范围,这将起作用 如果不是(可能是sizeof(int)=1),会发生什么 fgetc有时会从文件中读取
fgetc
:
int c;
while ((c = fgetc(file)) != EOF)
{
// do stuff
}
从理论上讲,如果文件中的某个字节的值为EOF
,则该代码存在错误-它将提前中断循环并无法处理整个文件。这种情况可能吗
据我所知,fgetc
在内部将从文件读取的字节强制转换为无符号字符,然后转换为int
,并返回它。如果int
的范围大于无符号字符的范围,这将起作用
如果不是(可能是sizeof(int)=1
),会发生什么
fgetc
有时会从文件中读取等于EOF
的合法数据吗
- 它是否会改变从文件中读取的数据,以避免使用单一值
EOF
fgetc
是否为未实现的函数
EOF
是否属于另一种类型,如long
我可以通过额外的检查使我的代码成为傻瓜:
int c;
for (;;)
{
c = fgetc(file);
if (feof(file))
break;
// do stuff
}
如果我想要最大的可移植性,这是必要的?C规范规定int
必须至少能够保存-32767到32767之间的值。任何具有较小int
的平台都是非标准的
C规范还指出,EOF
是一个负的int
常数,fgetc
在成功读取时返回“一个无符号字符
转换为int
”。由于unsigned char
不能有负值,因此可以将EOF
的值与从流中读取的任何值区分开来*
*请参见下文中的漏洞案例,在该案例中,这一点无法成立
相关标准文本(来自C99):
- §5.2.4.2.1整数类型的大小
:
实施定义值的大小(绝对值)应等于或大于所示值,且符号相同
[……]
- 类型为
int
INT\u MIN
-32767
- 类型为
int
INT_MAX
+32767
- §7.19.1
-简介
EOF
。。。扩展为一个整型常量表达式,类型为int
和一个负值,由多个函数返回以指示文件结束,即不再从流中输入
- §7.19.7.1
fgets
功能
如果未设置由stream
指向的输入流的文件结束指示符,并且存在下一个字符,fgetc
函数将该字符作为无符号字符
转换为int
并推进流的相关文件位置指示符(如果已定义)
如果UCHAR\u MAX
≤ INT_MAX
,没有问题:所有unsigned char
值都将转换为非负整数,因此它们与EOF不同
现在,这里有一个有趣的漏洞:如果系统有UCHAR\u MAX
INT\u MAX
,那么法律允许系统将大于INT\u MAX
的值转换为负整数(根据§6.3.1.3,将值转换为无法表示该值的有符号类型的结果由实现定义),使从流中读取的字符能够转换为EOF
具有CHAR\u BIT>8
的系统确实存在(例如,TI C4x DSP,它显然使用32位字节),尽管我不确定它们是否在EOF和流函数方面被破坏。注意:chux的答案在大多数情况下都是正确的。我将这个答案留待讨论,因为我相信答案和评论中的讨论对于理解chux的方法是必要的(罕见的)情况是有价值的。
EOF保证有一个负值(C99 7.19.1),正如您所提到的,fgetc在转换为int之前会将其输入作为无符号字符读取。因此,它们本身保证EOF不能从文件中读取
关于你的具体问题:
- fgetc无法读取等于EOF的合法数据。在文件中,没有签名或未签名的内容;它只是位序列。是C对10001111的解释不同,这取决于它被视为有符号还是无符号。fgetc需要将其视为无符号,因此不能返回负数(EOF除外)
附录:它不能读取无符号字符部分的EOF,但当它将无符号字符转换为int时,如果int不能表示无符号字符的所有值,则行为由实现定义(6.3.1.3)
- 托管实现的标准要求fgetc,但允许独立实现省略大多数标准库函数(有些显然是必需的,但我找不到列表)
- EOF不需要很长的时间,因为fgetc需要能够返回它,而fgetc返回int
- 就更改数据而言,它无法准确更改值,但由于fgetc被指定为从文件中读取“字符”,而不是从字符中读取,因此它可能一次读取8位,即使系统以其他方式将CHAR_位定义为16(如果sizeof(int),这是它可能具有的最小值)==1,因为5.2.4.2)要求INT_MIN=32767。在这种情况下,输入字符将被转换为始终具有高位0的无符号字符。然后它可以在不损失精度的情况下转换为int。(实际上,这不会出现,因为机器通常没有16位字节)
是,
c=fgetc(文件);如果(feof(file))
对最大端口有效
int c;
for (;;)
{
c = fgetc(file);
if (c == EOF) {
if (feof(file)) break;
if (ferror(file)) break;
}
// do stuff
}