【问题标题】:GNU-getline: strange behaviour about EOFGNU-getline:关于 EOF 的奇怪行为
【发布时间】:2014-08-21 10:09:05
【问题描述】:

测试

为了找出getline()遇到EOF时的行为,我写了如下测试:

int main (int argc, char *argv[]) {
    size_t max = 100;
    char *buf = malloc(sizeof(char) * 100);
    size_t len = getline(&buf, &max, stdin);
    printf("length %zu: %s", len, buf);
}

输入1是:

abcCtrl-D回车

结果:

 length 4: abc  //notice that '\n' is also taken into consideration and printed

输入2:

abc输入

完全相同的输出:

 length 4: abc

EOF 似乎被getline() 忽略了

源代码

所以我找到了source code of getline(),以下是它的相关sn-p(为了简洁起见,我省略了一些cmets和不相关的代码):

 while ((c = getc (stream)) != EOF)
{
  /* Push the result in the line.  */
  (*lineptr)[indx++] = c;

  /* Bail out.  */
  if (c == delim)             //delim here is '\n'
   break;
}

/* Make room for the null character.  */
if (indx >= *n)
{
  *lineptr = realloc (*lineptr, *n + line_size);
  if (*lineptr == NULL)
   return -1;
  *n += line_size;
}

/* Null terminate the buffer.  */
(*lineptr)[indx++] = 0;

 return (c == EOF && (indx - 1) == 0) ? -1 : indx - 1;

问题

所以我的问题是:

  • 为什么这里的长度是 4(据我所知应该是 5)(正如wiki 所说,如果它不在行首,就不会是 EOF)

类似的问题:EOF behavior when accompanied by other values 但请注意该问题中的 getline() 与 GNU-getline 不同

我使用 GCC:(Ubuntu 4.8.2-19ubuntu1) 4.8.2

【问题讨论】:

  • 作为测试,使用您的程序的二进制文件作为自己的输入:./a.out <a.out 它会报告一个很大的数字(当我尝试时:1317)。下一步:十六进制转储您的程序hexdump a.out | less 并查找第一个04 字符(在我的情况下它位于位置0x18)。结论:EOD (0x04) 字符不特殊。说明: EOD 只是由终端驱动程序处理不同。
  • 在这里查看我的答案:stackoverflow.com/a/10766343/905902 演示终端如何处理“特殊”字符(它是关于 ^C,而不是 ^D,但机制相似)
  • len 是 4,因为 (a + b + c + \n = 4)。无需使用ctrl+d。只需a b c [enter]
  • @wildplasser 抱歉这么晚了。谢谢。您能否详细解释一下您是如何得出结论的,因为我没有得到它。
  • 大部分内容都被@mafso 覆盖。我的重点是:没有 EOF 字符。 (有时)有一个 EOF condition ,它 sometimes 被翻译成一个具有 EOF 值的 int。 mafso 的反应涵盖了这种反应被延迟的情况(由终端/终端驱动程序/原始输入和程序之间的缓冲)

标签: c linux eof


【解决方案1】:

Ctrl-D 使您的终端刷新输入缓冲区(如果尚未刷新)。否则,设置输入流的文件结束指示符。换行符也会刷新缓冲区。

所以你没有关闭流,只是刷新了输入缓冲区,这就是getline 看不到文件结束指示符的原因。

在这两种情况下,getline 都不会收到文字 EOT 字符(ASCII 0x04,^D)(为此,您可以键入 Ctrl -VCtrl-D)。

类型

abcCtrl-DCtrl-D

abc回车Ctrl-D

实际设置文件结束指示符。

来自POSIX

特殊字符

  • EOF

输入中的特殊字符,如果设置了ICANON 标志,则可以识别该字符。收到后,所有等待读取的字节立即传递给进程,无需等待<newline>,并丢弃 EOF。因此,如果没有等待的字节(即,EOF 发生在行的开头),则应从read() 返回字节计数为零,表示文件结束指示。如果设置了ICANON,则处理时丢弃EOF字符。

仅供参考,ICANON 标志指定为 here

【讨论】:

  • 任何关于“Ctrl-D 导致终端刷新输入缓冲区”的参考资料?此外,维基百科说“驱动程序将行首的 Control-D 字符转换为文件结束指示符。”错了吗?
  • 似乎是准确的。如果你运行cat,输入一些文本而不按回车,然后按^D,cat 将立即回显你目前输入的内容。
  • 不幸的是,没有。我找到了this on Wikipedia,虽然没有参考。您从 Wikipedia 引用的内容没有错(也不与我相矛盾),只是不完整。它没有说明如果^D 不是在行首按下会发生什么。
  • POSIX: 如果使用转义 约定的实用程序在转义 之后立即检测到文件结束条件,则结果未指定。没那么有用,但 ^D 似乎是 POSIX 指定的。不过没找到。这个问题经常出现在这里,我发现的所有重复项也没有引用来源(而且大多数人根本没有提到当^D 不是在行首按下时会发生什么)。如果我们能找到它的来源/指定的地方,那就太好了。
  • 我认为我们同意。在问题的评论中查看我的./a.out <a.out 示例。顺便说一句,恕我直言,POSIX 中的措辞令人困惑,它使人们相信实际上存在 EOF 字符。事实上:CANON 模式可以改变终端的行为。
猜你喜欢
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 2012-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多