ana*_*lyg 4 c binaryfiles language-lawyer fgetc
我们经常使用fgetc这样的:
int c;
while ((c = fgetc(file)) != EOF)
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
从理论上讲,如果文件中的某个字节的值为EOF,则此代码存在错误 - 它会提前中断循环并且无法处理整个文件.这种情况可能吗?
据我所知,fgetc内部将从文件读取的字节转换为unsigned char然后int返回,并返回它.如果范围int大于的范围,这将起作用unsigned char.
如果不是(可能那么sizeof(int)=1)会发生什么?
fgetc读取一个等于EOF文件的合法数据吗?EOF吗?fgetc是一个未实现的功能?EOF是另一种类型long吗?我可以通过额外的检查使我的代码变得简单:
int c;
for (;;)
{
c = fgetc(file);
if (feof(file))
break;
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
如果我想要最大的便携性,这是必要的吗?
C规范说,int必须至少能够保持-32767到32767之间的值.任何较小的平台int都是非标准的.
C规范还说这EOF是一个负int常数,并且在成功读取时fgetc返回" unsigned char转换为int".由于unsigned char不能具有负值,因此EOF可以将值与从流中读取的任何内容区分开来.*
*请参见下文,了解未能解决的漏洞案例.
相关标准文本(来自C99):
§5.2.4.2.1整数类型的大小<limits.h>:
[]实现定义的值的大小(绝对值)应等于或大于所示的值,并带有相同的符号.
[...]
- 类型对象的最小值
int
INT_MIN-32767- 类型对象的最大值
int
INT_MAX+32767
§7.19.1 <stdio.h>- 简介
EOF...扩展为一个整数常量表达式,带有类型int和负值,由几个函数返回以指示文件结束,即不再有来自流的输入
§7.19.7.1 fgets函数
如果
stream未设置指向的输入流的文件结束指示符并且存在下一个字符,则该fgetc函数将该字符作为unsigned char转换为a获得int并前进该流的相关文件位置指示符(如果已定义)
如果为UCHAR_MAX≤ INT_MAX,则没有问题:所有unsigned char值都将转换为非负整数,因此它们将与EOF不同.
现在,这里有一个有趣的漏洞:如果系统有 UCHAR_MAX> INT_MAX,那么法律允许系统将值转换为大于INT_MAX负整数的值(根据§6.3.1.3,将值转换为无法签名的类型的结果表示该值是实现定义的),使得从流中读取的字符可以转换为EOF.
CHAR_BIT > 8确实存在的系统(例如TI C4x DSP,显然使用32位字节),虽然我不确定它们是否在EOF和流功能方面有所破坏.
是的,c = fgetc(file); if (feof(file))确实可以实现最大的便携性。它适用于一般情况,也适用于unsigned char和int具有相同数量的唯一值时。这发生在与罕见的平台char,signed char,unsigned char,short,unsigned short,int,unsigned全部采用相同的位宽度和范围宽度。
注意feof(file))是不够的。代码还应检查ferror(file).
int c;
for (;;)
{
c = fgetc(file);
if (c == EOF) {
if (feof(file)) break;
if (ferror(file)) break;
}
// do stuff
}
Run Code Online (Sandbox Code Playgroud)