【问题标题】:Sensible line buffer size in C?C中合理的行缓冲区大小?
【发布时间】:2010-08-23 22:09:05
【问题描述】:

我正在使用 popen 来读取 shell 命令的输出。我将使用 fgets 逐行阅读。 我的问题是如何为我的 char* 缓冲区选择最佳缓冲区大小?我记得一位教授告诉我们要包括<limits.h> 并使用LINE_MAX 来处理这些事情。它在我的 Mac 上运行良好,但在 Linux 上没有 LINE_MAX

这个邮件列表存档提出了同样的问题,但没有回答我的问题 http://bytes.com/topic/c/answers/843278-not-able-locate-line_max-limits-h

【问题讨论】:

    标签: c file-io buffer fgets


    【解决方案1】:

    <limits.h>没有定义LINE_MAX时,看_POSIX2_LINE_MAX,要求至少是2048,我一般用4096。

    同时寻找(新的)POSIX 函数 getline()getdelim() - 都在同一个 URL。这些会根据需要分配内存。


    程序 (posix2_line_max.c)

    #include "posixver.h"
    #include <limits.h>
    #include <stdio.h>
    
    int main(void)
    {
      printf("%d\n", _POSIX2_LINE_MAX);
      return 0;
    }
    

    输出:

    2048
    

    posixver.h

    #ifndef JLSS_ID_POSIXVER_H
    #define JLSS_ID_POSIXVER_H
    
    /*
    ** Include this file before including system headers.  By default, with
    ** C99 support from the compiler, it requests POSIX 2001 support.  With
    ** C89 support only, it requests POSIX 1997 support.  Override the
    ** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
    */
    
    /* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
    /* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
    /* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */
    
    #if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
    #if __STDC_VERSION__ >= 199901L
    #define _XOPEN_SOURCE 600   /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
    #else
    #define _XOPEN_SOURCE 500   /* SUS v2, POSIX 1003.1 1997 */
    #endif /* __STDC_VERSION__ */
    #endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */
    
    #endif /* JLSS_ID_POSIXVER_H */
    

    在 Ubuntu 12.04 衍生版本上测试;命令行:

    gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror  posix2_line_max.c -o posix2_line_max
    

    【讨论】:

    • 两者都没有定义。我尝试在包含标题limits.h 之前定义宏__USE_POSIX2__USE_POSIX__USE_XOPEN,但无济于事:(我使用的是Ubuntu 12.10。
    • @ajay:您尝试设置的宏完全由编译系统控制,用于自己的目的;它们在编译开始时完全重置,然后由系统根据您为控制编译而设置的标志进行设置。大多数情况下,您需要设置 _XOPEN_SOURCE_POSIX_C_SOURCE - 请参阅添加到答案中的代码。或_GNU_SOURCE 或...
    • 非常感谢 :) 您是 SO 上C 中所有问题和疑问的一站式解决方案。 :) 最后一个问题。使用大于LINE_MAX 的缓冲区好吗?就像你说的,你通常使用 4096。
    • 是的;它只是一个下限。你做出判断。如果您认为您可能正在处理没有换行符的数据(JSON?HTML?Javascript?),那么您必须担心限制。如果您不处理没有换行符的数据,那么您可以负担得起变小。这是一个复杂的决定。您需要担心检查是否有换行符(或使用getline())。在某种程度上,我使用 4096 来表示震撼值,以使人们摆脱 80 字节或 256 字节的心态。具有千兆字节主内存的机器不会受到 4k 缓冲区的伤害(在相当广泛的范围内)。
    【解决方案2】:

    man getline

    另见http://www.gnu.org/s/libc/manual/html_node/Line-Input.htmlgetline()fgets()gets() 的讨论。受到 SO 的影响比我想象的还要多。

    【讨论】:

      【解决方案3】:

      您可以使用malloc() 并在必要时进行扩展,或者使用源代码并查看 GNU 实用程序是如何做到的。

      【讨论】:

      • 好的,我会检查一个 GNU 实用程序。我正在使用 malloc,但只使用了一次,并且重复使用了相同的行缓冲区。
      • 我总是在 GNU 或优秀的开源项目中寻找代码。或者你可以动态地增加堆空间(到一个点),但这可能很慢(把所有东西都复制回来)。
      【解决方案4】:

      检查该行是否有“\n”,如果不存在,请在调用下一个 fget 之前扩展缓冲区。

      【讨论】:

      • 如果没有'\n',您还需要检查feof(),以说明文件中最后一行没有尾随换行符的极端情况。
      【解决方案5】:

      POSIX 系统有getline,它会为你分配一个缓冲区。

      在非 POSIX 系统上,您可以使用 Chuck B. Falconer 的公共域 ggets 函数,类似。 (Chuck Falconer 的网站不再可用,虽然archive.org has a copy,我已经制作了my own page for ggets。)

      【讨论】:

      • 实现一个可移植且快速的getline 也很容易,它完全支持嵌入的空字符,就像原始的GNU 版本一样,只使用reallocfgetsmemset,和memchr。这可能比ggets 好很多,ggets 似乎破坏了换行符/文件结尾的行为并且无法处理嵌入的空值,但这实际上取决于您的应用程序和您的需求。
      • @R..: AFAIK 没有任何与 ggets 相关的 EOF 问题,虽然它确实不能处理嵌入式 NUL,但我认为这不是一个常见的用例。 (这也不是fgets 直接支持的东西,我不确定你将如何围绕fgets 构建一些东西来区分嵌入的 NUL 字节和实际的结尾。它当然不像你做的那么微不足道出来。)
      • 您到底如何使用ggets 区分以换行符结尾的最后一行和缺少换行符的最后一行?如果你不能,那么它是一个有损函数。对于许多用途而言,损失可能无关紧要,但我仍然认为这是一个主要限制。至于fgets 和嵌入的空值,这很容易。在调用fgets 之前使用'\n' 设置缓冲区,然后使用memchr 搜索'\n' 会告诉您读取了多少字节。
      • 关于ggets 的损失的好点。 OTOH,我个人见过更多fgets 消费者错误地去掉尾随换行符的情况,而不是我见过他们关心保留丢失的'\n' 的情况。至于检测嵌入式 NUL,很聪明,但一种病态的实现可能会在每次非空读取时填满整个缓冲区。
      • 不,标准规定了fgets 的作用,这在形式上相当于重复调用fgetc 并将结果存储在缓冲区中,直到缓冲区满或遇到\n。超过这一点的写作不符合规范。
      猜你喜欢
      • 1970-01-01
      • 2011-11-26
      • 2017-04-07
      • 1970-01-01
      • 2016-12-30
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多