在C语言中,合理的行缓冲区大小是多少?

4
我正在使用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
5个回答

6

<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

1
它没有定义。我尝试在包含头文件limits.h之前定义宏__USE_POSIX2__USE_POSIX__USE_XOPEN,但是都没有用:( 我正在使用Ubuntu 12.10。 - ajay
2
@ajay:你尝试设置的宏完全受编译系统控制,用于它自己的目的;它们在编译开始时被完全重置,然后根据你设置的标志来由系统设置以控制编译。大多数情况下,您需要设置“_XOPEN_SOURCE”或“_POSIX_C_SOURCE”——请参见答案中添加的代码。或者设置“_GNU_SOURCE”或… - Jonathan Leffler
非常感谢你 :) 你是在SO上关于C语言所有问题和疑惑的一站式解决方案。:) 只有一个最后的问题。使用比LINE_MAX更大的缓冲区是否可以?就像你说的通常使用4096一样。 - ajay
2
是的,这只是一个下限。你需要做出判断。如果你认为你可能会处理没有换行符的数据(JSON?HTML?Javascript?),那么你就必须担心限制问题。如果你不处理没有换行符的数据,你可以使用更小的缓冲区。这是一个复杂的决定。你需要担心检查是否得到了换行符(或者使用getline())。部分原因,我使用4096来引起震惊,让人们摆脱80字节或256字节的固有思维。具有几GB主存储器的计算机不会受到4k缓冲区的影响(在相当广泛的范围内)。 - Jonathan Leffler

5

0
你可以使用 malloc() 并在必要时进行扩展,或者查看源代码并了解 GNU 实用程序如何处理它。

好的,我会查看一个GNU实用工具。我正在使用malloc,但仅一次,并重复使用相同的行缓冲区。 - Derrick
我总是在GNU或好的开源项目中寻找代码。或者你可以动态地增加堆空间(到一定程度),但这可能会很慢(需要复制所有内容)。 - Vince

0
检查行中是否存在'\n',如果不存在,请在调用下一个fgets之前扩展缓冲区。

1
你还需要检查feof()是否存在'\n',以处理文件中最后一行没有尾随换行符的边缘情况。 - caf

0

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

在非POSIX系统上,您可以使用Chuck B. Falconer的公共领域ggets函数,它类似于getline。(Chuck Falconer的网站不再可用,尽管archive.org有一份拷贝,我也制作了自己的ggets页面。)


实现一个便携且快速的 getline,支持嵌入式空字符,就像原始的GNU版本一样,只需要使用 reallocfgetsmemsetmemchr 就可以了。这可能比 ggets 更好,因为 ggets 在处理换行符/文件结尾时似乎存在问题,并且无法处理嵌入式空字符,但这真的取决于您的应用程序和需求。 - R.. GitHub STOP HELPING ICE
@R..:据我所知,使用ggets不再存在EOF问题,虽然它确实不能处理内嵌的NUL字符,但我认为这不是一个常见情况。(这也不是fgets直接支持的事情,而且我不确定如何在fgets周围构建一个可以区分内嵌NUL字节和实际结尾的东西。它看起来并不像你描述的那样简单。) - jamesdlin
@R..:你能告诉我在哪里写到了吗?因为C99标准中的7.19.7.2没有提到这样的内容。 - jamesdlin
我是根据与ISO C99对齐的POSIX文档进行操作的。用fgetcfputc来指定所有内容可能是一种POSIX主义,但您提供的引用清楚地指定了写入数组的内容(“最多少于n个字符指定的数量”后跟一个终止空字符)。标准库函数不能随意破坏它们规定之外的内存。 - R.. GitHub STOP HELPING ICE
嗯,规范明确说明了写入内存的内容;否则符合规范的实现可以只读取并丢弃所有字符。除非规范说明在调用 fgets 后缓冲区其余部分的内容是未指定的,否则 fgets 不能 破坏它。 - R.. GitHub STOP HELPING ICE
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接