【问题标题】:*Might* an unsigned char be equal to EOF? [duplicate]*可能* unsigned char 等于 EOF? [复制]
【发布时间】:2015-07-10 15:16:05
【问题描述】:

当使用fgetc 读取流的下一个字符时,您通常会检查文件结尾不是由

if ((c = fgetc (stream)) != EOF)

其中c 属于int 类型。然后,要么已达到文件结尾且条件将失败,要么c 应为unsigned 字符转换为int,预计与EOF 不同——对于EOF确保为负。好吧……显然。

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

我错了吗?如果未达到文件结尾,C 标准中是否有阻止fgetc 返回EOF 的内容? (如果是,我找不到它!)。还是if ((c = fgetc (stream)) != EOF) 语法不完全可移植?...

编辑:确实,这是问题 #3860943 的副本。我在第一次搜索时没有找到那个问题。感谢您的帮助! :-)

【问题讨论】:

标签: c char eof unsigned fgetc


【解决方案1】:

如果您正在读取仅标准 ASCII 的流,则不会在真正的文件结束之前收到等效于 EOF 的字符,因为有效的 ASCII 字符代码最多只能达到 127。但它可能在读取二进制文件时发生。该字节需要为 255(无符号)才能对应于 -1 有符号字符,并且没有什么可以阻止它出现在二进制文件中。

但是关于您的具体问题(如果标准中有某些内容),不完全是......但请注意 fgetc 将字符提升为无符号字符,因此在这种情况下它永远不会是负面的。唯一的风险是,如果您显式或隐式地将返回值转换为有符号字符(例如,如果您的 c 变量是有符号字符)。

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

【讨论】:

  • 请注意,例如不过,0xFFFFFFFF == -1 的测试对于 32 位 ints 来说是正确的。通常的算术转换将 -1 转换为 unsigned int
  • @Ulfalizer,我的意思正好相反。如果 fgetc 找到要读取的 0xFF 字节,它将被提升为 0x000000FF(因此为正 255),而不是 0xFFFFFFFF,因为它被提升为无符号字符。在此处查看 fgetc 实现的示例:mirror.fsf.org/pmon2000/3.x/src/lib/libc/fgetc.c
  • 但是 C 并不仅限于 ASCII。
  • @FabioCeconello:如果charint 具有相同的大小,那么您最终可能会得到例如一个 0xFFFFFFFF char 值。我猜这个标准可能在一些地方暗示(ish)该值应该可以表示为签名的int。无论如何,从无符号转换为有符号都是未定义的行为。
  • 当值不适合有符号类型时。
【解决方案2】:

我认为你需要依赖流错误。

ch = fgetc(stream);
if (ferror(stream) && (ch == EOF)) /* end of file */;

来自the standard

如果发生读取错误,设置流的错误指示器并且 fgetc 函数返回 EOF。


修改为更好的版本

ch = fgetc(stream);
if (ch == EOF) {
    if (ferror(stream)) /* error reading */;
    else if (feof(stream)) /* end of file */;
    else /* read valid character with value equal to EOF */;
}

【讨论】:

  • 我不认为达到 eof 是读取错误。
  • 也许不是……总有feof()
  • 问题实际上是:如果没有到达文件结尾并且没有读取错误,是否允许实现ch == EOF为真?
【解决方案3】:

你问:

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.
}

【讨论】:

  • sizeof(int) == 1 时,我喜欢if ( !feof(stream) && !ferror(stream) ) 测试。 +1 便携式通用解决方案。
【解决方案4】:

我同意你的阅读。

C 标准说 (C11, 7.21.7.1 The fgetc function p3):

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 2013-08-10
    相关资源
    最近更新 更多