EOF是否总是负数?

9

EOF是否总是负数?

我正在考虑编写一个函数,该函数读取输入中的下一个单词并返回找到单词的行号,如果已经到达输入的结尾,则返回EOF。如果EOF不一定是负数,则该函数将不正确。


2
为什么你需要从自己的函数中返回EOF?只需将函数定义为“返回找到单词的行号,如果到达输入结尾则返回-1”。尽管如此,许多来源(例如《代码大全》)都警告不要混合返回值和失败代码。 - Martin B
没错,这是一个可能的且完全可行的替代方案。不过,我认为EOF会更加明确。 - Ree
6个回答

16

EOF永远等于EOF。不要假设其他任何东西。

在第二次阅读标准时(并根据这里的一些其他评论),似乎EOF始终为负数-对于本问题中指定的用途(行号或EOF),它将起作用。我想警告的是(并且仍然是)假定字符为正数而EOF为负数。

请记住,符合标准的C实现可以具有负字符值-甚至在“C编程语言”(K&R)中提到过这一点。打印字符始终为正数,但在某些体系结构(可能是所有古代的),控制字符为负。 C标准未指定char类型是有符号还是无符号,并且保证跨平台具有相同值的唯一字符常量是'\0'


你能添加一些参考资料吗? - Guillaume
6
这不正确。EOF宏必须扩展为一个负整数,但很遗憾我现在手头没有标准的副本。 - CB Bailey
C库参考手册称,它几乎所有的信息都来自ANSI C标准,并表示“EOF是一个负整数,表示已到达文件结尾”(http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.12.html#variables)。尽管如此,我仍然认为假设EOF为负数既不好看,而且也没有必要。 - Martin B
控制字符通常不是负数。如果您的普通char类型是有符号的,并且代码集是EBCDIC,则将'A'(0xC1,191)的char值直接提升为int所得到的值为负数;如果您先将其提升为无符号char,然后再提升为int,则它将是正数,当然。 - Jonathan Leffler
基本执行字符集中的所有成员都是正数。 - Johannes Schaub - litb
细节:“在各个平台上保证具有相同值的唯一字符常量是'\0'”,'\1''\2''\3' ... '\x1''\x2'也具有相同的跨平台值,以及L'...'u'...'U'...'变体。 - chux - Reinstate Monica

12

是的,EOF始终为负数。

标准规定:

7.19 输入/输出
7.19.1 引言

3 这些宏是:[...] EOF,该宏扩展为一个整型常量表达式,具有int类型和负值,由多个函数返回,表示文件结尾,即从流中没有更多输入;

请注意,“普通”char被视为带符号的没有任何问题。<stdio.h>处理char的函数会将字符强制转换为unsigned char类型,然后转换为int类型,因此所有有效字符都具有正值。例如:

int fgetc(FILE *stream)

7.19.7.1
... fgetc函数将该字符作为无符号字符转换为int获取...


3
如果sizeof(char) == sizeof(int),那么就存在一个问题,即使通过unsigned char进行强制转换也不能保证所有有效的char值都是正数。幸运的是,这种情况相对较少发生。 - CB Bailey
只有当你错误地假设负值总是EOF(if (ch < 0) /* EOF detected */;),或者"执行字符集"使用了从INT_MIN0的所有值时,才会出现这个问题,在这种情况下,EOF值与有效字符的值相同。 - pmg

8

让该函数返回:

  • 单词所在的行号
  • 如果已到达输入的末尾,则返回-1

这样问题就解决了,不需要依赖任何EOF值。调用者可以轻松测试是否成功调用,并假定EOF/IO错误。


2
在线草案 n1256,17.9.1.3:

EOF(End of File)

它是一个带有负值的整数常量表达式,其类型为 int,在多个函数中返回以表示文件结束,即没有流中的更多输入;

EOF 始终是负数,尽管它可能不是 -1。

对于这样的问题,我更喜欢通过将错误条件和数据分离来返回错误代码(如 SUCCESSEND_OF_FILEREAD_ERROR 等)作为函数的返回值,然后将感兴趣的数据写入单独的参数,例如:

int getNextWord (FILE *stream, char *buffer, size_t bufferSize, int *lineNumber)
{
  if (!fgets(buffer, bufferSize, stream))
  {
    if (feof(stream)) return END_OF_FILE; else return READ_ERROR;
  }
  else
  {
    // figure out the line number
    *lineNumber = ...;
  }
  return SUCCESS;
}      

1

EOF是一种状态,而不是一个值。这个哨兵的确切值是由实现定义的。在很多情况下,它是一个负数。


在很多情况下,它是一个负数。我建议将所有情况都考虑进去,因为C语言确实指定了"EOF扩展为整数常量表达式,类型为'int'且具有负值..." - chux - Reinstate Monica

1

1
维基百科这里并不完全正确。EOF可以是-1,而对于带符号字符来说,一个字符的值可以是-1(例如在windows-1252中的欧元符号)。事实上,(f)getc 的返回值是下一个字符被转换为无符号字符,然后转换为int,而且这个值不应该与EOF匹配。当然,这只有在sizeof(int) != sizeof(char)的情况下才能起作用。 - CB Bailey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接