【问题标题】:POSIX getline() - line buffer state on EOF?POSIX getline() - EOF 上的行缓冲区状态?
【发布时间】:2017-05-14 21:54:04
【问题描述】:

这个问题是关于 POSIX C 函数getline

文档指出 getline 在错误(包括 EOF)时返回 -1,但没有说明在这些情况下 lineptrn 会变成什么。
我知道某些错误的处理方式可能不同 - 例如失败的realloc - 但是EOF呢? lineptrn 是否仍保留其原始值?它是特定于实现的吗?未定义的行为?

【问题讨论】:

    标签: c posix getline


    【解决方案1】:

    如果 getline 返回错误(EOF 是此函数中的错误)。不应使用缓冲区中的数据。

    如果函数读取至少 1 个字节,则不得返回EOF,注意函数在某些情况下可以返回 0。

    另外,manual 明确表示:

    即使 getline() 失败,用户程序也应释放此缓冲区。


    在任何一种情况下,调用成功后,*lineptr 和 *n 都会被更新 分别反映缓冲区地址和分配的大小。

    这句话可以理解为缓冲区只有在调用成功时才会更新。


    在我看来,程序应该记录这个错误并继续读取已经读取的数据。注意:使用feof() 可以知道流是否已到达末尾。

    【讨论】:

    • 我同意当getline 失败时应该释放缓冲区,但这仍然没有说明失败时缓冲区内容的状态。无论哪种方式,在-1 return 定义明确之后,这听起来不像访问缓冲区,所以我最好不要依赖它。
    • @Mr.Llama 顺便说一句,我真的不明白你为什么想知道EOF。为什么getline()无错误返回时,要保留已经解析过的缓冲区中的数据?想了想,这看起来像是一个 XY 问题。
    • 我有一个单行缓冲区,我想在 EOF 之前打印最后一整行。问题是如果getline 为EOF 返回-1,我不能保证我的行缓冲区对于打印仍然有效。现在我正在通过使用两个行缓冲区来解决它。
    • GNU docs gnu.org/software/libc/manual/html_node/Line-Input.html 说“如果发生错误或在没有读取任何字节的情况下到达文件末尾,getline 返回-1。”在我看来,即使最后一行确实如此不以换行符结尾,函数将返回读取的字符数(而不是-1)。另一方面,Linux 文档没有这样说,所以也许你应该创建一个文本文件,其中最后一行不以换行符结尾并测试会发生什么。
    • @Stuart 这个人也这么说:“缓冲区以空值结尾,并且包括换行符,如果找到的话。”。
    【解决方案2】:

    如果您查看这些 POSIX 文档 http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html 如果函数读取流中的最后一行并且 EOF 发生时没有换行符(即最后一行没有换行符),您将看到该函数不会返回 -1。因此,当您到达 EOF 时,缓冲区的内容无关紧要,因为 getline 不会向其中写入任何内容。

    【讨论】:

    • “所以当你到达 EOF”可能更清楚地理解为“所以当函数返回 -1 因为 EOF”因为即使字节被读取和写入缓冲区也可以达到 EOF .
    • @ChronoKitsune 是的,这可能更好,尽管 POSIX 文档说得很清楚。我可能不应该尝试解释文档。
    【解决方案3】:

    lineptrn 的值是特定于实现的。 getline() 函数在读取 EOF 时可能会也可能不会重新分配缓冲区。

    我以 Illumos、NetBSD 和 FreeBSD 为例。我看 getdelim() 因为所有 3 个系统都有 getline() 调用 getdelim() 和分隔符'\n'。

    • Illumos getdelim() 在调用 __filbuf 读取文件之前,总是会尝试至少 128 字节的缓冲区。因此,如果您传入 *lineptr = NULL 并读取 EOF,您将返回指向 128 字节垃圾的 *n = 128*lineptr
    • NetBSD getdelim() 总是调用 __srefill 来读取文件,然后再尝试重新分配。如果它读取 EOF,您将返回您传入的 *lineptr。如果您传入 *lineptr = NULL,NetBSD 确实设置了 *n = 0
    • FreeBSD getdelim() 也在重新分配之前读取,但如果它读取 EOF,那么它会在缓冲区中放置一个 '\0' (用于空字符串)。如果*lineptr 为NULL,FreeBSD 分配一个1 字节的缓冲区。这与 NetBSD 和 Illumos 不同,因为这些系统不会将空字符串放入缓冲区。

    总之,当 getline() 读取 EOF 时,*lineptr 的值可能会发生变化,也可能不会发生变化,它可能会或可能不会指向空字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      • 1970-01-01
      • 2016-12-30
      • 1970-01-01
      • 2014-11-26
      相关资源
      最近更新 更多