*可能*未签名的字符等于EOF?

时间:2015-04-30 19:12:07

标签: c char eof unsigned fgetc

使用fgetc读取流的下一个字符时,通常会检查

是否未达到文件结尾
if ((c = fgetc (stream)) != EOF)

其中c属于int类型。然后,文件结束已经达到并且条件将失败,或者c应该是转换为unsigned的{​​{1}}字符,预计与int不同1}} -for EOF被确定为否定。很好......显然。

但是存在一个小问题...通常EOF类型不超过8位,而char必须至少有16位,因此每个int都可以表示作为unsigned char。然而,在int将有16或32位的情况下(我知道,实际上情况从未如此......),没有理由为什么不能有char,所以它(理论上!)可能sizeof(int) == 1返回fgetc (stream)(或另一个负值),但文件结尾尚未达到......

我错了吗?如果未达到文件结尾,C标准中是否会阻止EOF返回fgetc? (如果是的话,我找不到它!)。或EOF语法不完全可移植?...

编辑:的确,这是问题#3860943的重复。我在第一次搜索时没有找到这个问题。谢谢您帮忙! : - )

3 个答案:

答案 0 :(得分:2)

如果您正在读取仅标准ASCII的流,那么在真正的文件结束之前没有接收相当于EOF的字符的风险,因为有效的ASCII字符代码最多只能达到127。但是读取二进制文件时可能会发生这种情况。该字节需要为255(无符号)以对应-1签名字符,并且没有任何东西阻止它出现在二进制文件中。

但是关于你的具体问题(如果标准中有什么内容),不完全是......但请注意fgetc将字符作为无符号字符提升,因此它不会对此产生负面影响无论如何。唯一的风险是,如果您明确或隐式地将返回值转换为signed char(例如,如果您的c变量是signed char)。

注意:正如@Ulfalizer在评论中提到的那样,在一个罕见的情况下,您可能需要担心:如果sizeof(int)== 1,并且您正在读取包含非文件的文件-ascii字符,那么你可能得到一个不是真正的EOF的-1返回值。请注意,发生这种情况的环境非常罕见(据我所知,低端8位微控制器的编译器,如8051)。在这种情况下,安全选项是将feof()测试为@pmg建议。

答案 1 :(得分:2)

你问:

  

如果未达到文件结尾,C标准中是否会阻止fgetc返回EOF

相反,标准明确允许在发生错误时返回EOF

  

如果发生读取错误,则设置流的错误指示符,fgetc函数返回EOF

在脚注中,我看到了:

  

使用feofferror函数可以区分文件结束和读取错误。

您还问:

  

if ((c = fgetc (stream)) != EOF)语法不完全可移植?

CHAR_BIT大于8且sizeof(int) == 1的理论平台上,这不是检查已达到文件结尾的有效方法。为此,您必须诉诸feofferror

c = fgetc (stream);
if ( !feof(stream) && !ferror(stream) )
{
  // Got valid input in c.
}

答案 2 :(得分:1)

我同意你的阅读。

C标准说(C11,7.21.7.1 fgetc函数p3):

  

如果设置了流的文件结束指示符,或者流位于文件结尾,则设置流的endof-file指示符并且fgetc函数返回EOF。否则,fgetc函数返回stream指向的输入流中的下一个字符。如果发生读取错误,则设置流的错误指示符和fgetc函数   返回EOF。

标准中没有任何内容(假设UCHAR_MAX > INT_MAX)不允许托管实现中的fgetc返回等于EOF的值,该值既不是文件结尾也不是错误状态指示器。