【问题标题】:EOF missing for unix file [duplicate]unix 文件缺少 EOF [重复]
【发布时间】:2012-09-06 04:04:56
【问题描述】:

可能重复:
fgetc does not identify EOF
fgetc, checking EOF

我创建了一个文件并在 Unix 中将其命名为“file.txt”。我试图从我的 C 程序中读取文件内容。我无法接收 EOF 字符。 Unix不在文件创建时存储EOF字符?如果是这样,那么使用 C 从 Unix 创建的文件中读取 EOF 的替代方法是什么。

这是代码示例

int main(){
File *fp;
int nl,c;
nl =0;
fp = fopen("file.txt", "r");
while((c = fgetc(fp)) != EOF){
  if (c=='\n')
    nl++;
}
return 0; 
}

如果我明确给出 CTRL + D,即使我使用 char c,也会检测到 EOF。

【问题讨论】:

  • fgetc does not identify EOF 的可能重复项,另请参阅 stackoverflow.com/questions/11057259/fgetc-checking-eof 和许多其他人
  • 另请注意:EOF 不是“存储在文件中”,它只是 I/O 函数告诉您它们已到达文件末尾的一种方式。最后没有存储魔术字节。
  • 注意它应该是FILE *fp;而不是File *fp;,并且在通过变量fp读取任何内容之前,您还应该检查文件是否已成功打开。

标签: c unix


【解决方案1】:

记住:fgetc() 返回 int,而不是 char。它必须返回一个int,因为它的返回值集包括所有可能的有效字符以及一个单独的(负)EOF 指示符。

如果您将char 用于c 而不是int,则有两种可能的陷阱:

  1. 如果类型 char 使用您的编译器签名,您将检测到一个有效字符作为 EOF。通常,字符 ÿ(y-变音符号,在 Unicode 中正式称为 LATIN LOWER CASE Y WITH DIAERESIS,U+00FF,在 ISO 8859-1 又名拉丁 1 代码集中的十六进制代码 0xFF)将被检测为等效于 EOF,当这是一个有效的字符。

  2. 如果char 类型是无符号的,那么比较永远不会为真。

这两个问题都很严重,都可以通过使用正确的类型来避免:

FILE *fp = fopen("file.txt", "r");
if (fp != 0)
{
    int c;
    int nl = 0;
    while ((c = fgetc(fp)) != EOF)
        if (c == '\n')
            nl++;
    printf("Number of lines: %d\n", nl);
}

请注意,类型是FILE,而不是File。请注意,在尝试通过fp 读取之前,您应该检查文件是否已打开。


如果我明确给出 CTRL + D,即使我使用 char c,也会检测到 EOF。

这意味着您的编译器为您提供了char 作为签名类型。这也意味着您将无法准确计算包含 ÿ 的文件中的行数。


与 CP/M 和 DOS 不同,Unix 不使用任何字符来表示 EOF;当没有更多字符要读取时,您会到达 EOF。让很多人感到困惑的是,如果你在终端输入某个组合键,程序就会检测到 EOF。实际发生的是终端驱动程序识别字符并将任何未读字符发送到程序。如果没有未读字符,则程序返回 0 个字节,这与到达文件末尾时得到的结果相同。因此,字符组合(通常,但不总是,Ctrl-D)似乎向程序“发送 EOF”。但是,如果您使用cat >file,则字符不会存储在文件中;此外,如果您读取包含 control-D 的文件,那是一个字节值为 0x04 的完美字符。如果一个程序生成一个 control-D 并将其发送给一个程序,这并不表示该程序的 EOF。它是 Unix 终端(tty 和 pty — 电传打字机和伪电传打字机 — 设备)的严格属性。

【讨论】:

    【解决方案2】:

    如果c 的类型是char(并且char 在您的编译器中是无符号的,您可以通过检查CHAR_MIN in 的值而不是int 来检查这一点),就会发生这种情况。

    根据 C 标准,EOF 的值是负数。

    因此,将EOF 隐式转换为unsigned char 将丢失EOF 的真实值,并且比较总是会失败。

    更新:必须首先解决一个更大的问题。在表达式c = fgetc(fp) != EOF 中,首先计算fgetc(fp) != EOF(为0 或1),然后将值分配给c。如果文件中至少有一个字符,fgetc(fp) != EOF 将评估为 0,while 循环的主体将永远不会执行。您需要添加括号,例如:(c = fgetc(fp)) != EOF

    【讨论】:

      【解决方案3】:

      缺少括号。应该是:

      while((c = fgetc(fp)) != EOF)
      

      【讨论】:

      • 这会阻止代码编译 - 但不会解释运行时错误。它也告诉我们,问题中的代码不是编译出来的代码,这总是让调试变得更加困难。
      • 这将如何阻止代码编译?将不等式运算符的结果值赋给标量变量是完全有效的 C.
      【解决方案4】:

      您没有说明如何声明变量 c,它应该是 int 类型,而不是 char

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-11
        • 1970-01-01
        • 2013-05-25
        • 2021-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多