为什么要为 getline 或类似功能使用自己的缓冲区?

Why should I use my own buffer for getline or similar functions?

前几天我在写一个程序,我使用了 getline() 函数,我意识到一些我以前从未想过并且在网上找不到任何关于它的东西。

根据手册页中 getline 的描述:

DESCRIPTION

The getdelim() function reads a line from stream, delimited by the character delimiter. The getline() function is equivalent to getdelim() with the newline character as the delimiter. The delimiter character is included as part of the line, unless the end of the file is reached.

The caller may provide a pointer to a malloced buffer for the line in *linep, and the capacity of that buffer in *linecapp. These functions expand the buffer as needed, as if via realloc(). If linep points to a NULL pointer, a new buffer will be allocated. In either case, *linep and *linecapp will be updated accordingly.

通常当我使用这个函数时,我总是 malloc 我自己的缓冲区并将它传递给 getline 函数但是在阅读这篇文章之后我意识到这不是必需的,因为一个将被创建。

我的问题是:我应该创建自己的缓冲区然后将其传递给 getline,而不是只传递 NULL 并让 getline 处理缓冲区吗?

我能想到的唯一原因是,如果您想控制缓冲区的大小,但这似乎不正确,因为它说它将根据需要调整缓冲区的大小。

什么时候应该使用自己的缓冲区,什么时候应该让 getline 处理缓冲区的创建?

  1. 没有理由,缓冲区是 reallocd 需要的,你应该 free 自己。所以你可以通过 NULL 确保通过 length == 0.

  2. 我看不出有什么情况可以使用你自己分配的缓冲区,无论如何你都会使用 malloc,这就是 getline getdelim 也会用。

当然,如果您传递足够大的缓冲区,您将不会在每个 getline 上调用 realloc,但您可以使用 valgrind 进行测试,对于最常见的情况,将会有尽可能少地调用 realloc.

问:为什么我应该创建自己的缓冲区然后将其传递给 getline 而不是只传递 NULL 并让 getline 处理缓冲区?
答:通常不会。在某些 select 情况下,在调用 getline().

之前进行分配是有意义的

1) 许多getline() 重新分配方案都是线性的。也就是说,它将分配一个 N 字节的缓冲区(例如 256、1k、4k)。然后,如果这不够大,它将尝试 2*N、3*N、4*N、5*N 等。如果出于某种原因,代码预期定期需要大缓冲区,则在调用之前分配一个大缓冲区 getline() 将防止 getline() 重复重定位小缓冲区。一个潜在的,如果可疑的,效率改进。

  size_t size = 10000;
  char *buf = mallc(size);
  ssize_t numchar = getline(&buf, &size, ...);

2) 如果代码在调用 getline() 之前需要或有可用的工作缓冲区,则可以使用它。

  size_t size = 100;
  char *buf = mallc(size);
  ...
  foo(buf, size);
  ...
  // No need for these steps
  // free(buf);
  // size = 0;
  // buf = NULL;
  ...
  ssize_t numchar = getline(&buf, &size, ...);
  ...
  free(buf);

3) 反复来电。这包括一个重复调用 getline() 的循环。不需要在循环内释放,等到循环完成。 @艾伦斯托克斯

  // do not use this
  while (some_condition) {
    size_t size = 0;
    char *buf = NULL;
    ssize_t numchar = getline(&buf, &size, ...);
    foo(numchar, buf,size);
    free(buf);
  }  

  // instead, use this model
  size_t size = 0;
  char *buf = NULL;
  while (some_condition) {
    ssize_t numchar = getline(&buf, &size, ...);
    foo(numchar, buf,size);
  }  
  free(buf);

Q2:什么时候应该使用自己的缓冲区,什么时候应该让 getline 处理缓冲区的创建?
A2:当代码肯定需要或从中受益时,分配您自己的缓冲区。否则让 getline() 去做。