标准输出的缓冲区处理

Buffer handling for stdout

我尝试对终端输出函数进行单元测试。该函数将数据流式传输到标准输出,所以我的想法是控制标准输出缓冲区并检查该函数是否正确地将正确的数据写入缓冲区。

setvbuf 在我看来是实现这一目标的理想之选。

我使用 setvbuf 重定向标准输出以使用我自己指定的缓冲区。

我使用了流模式 _IOFBF,因此理论上只有在缓冲区已满时才会发生内部刷新。我系统上的 BUFSIZ 大小为 8192 字节...这对于被测函数的输出来说已经绰绰有余了,在调用期间没有内部刷新。

我的来源目前看起来像:

char buffer [BUFSIZ] = {0};

/* any outputs before redirecting */
printf("0\n");

/* output any remaining data */
fflush(stdout); 
/* redirect to my buffer with full buffering */
setvbuf(stdout,buffer,_IOFBF,BUFSIZ); 

/* testcode ... output of the function under test */
printf("1\n");
printf("2\n");

/* output any remaining data */
fflush(stdout);
/* restore internal buffering with line buffering */
setvbuf(stdout,NULL,_IOLBF,BUFSIZ);

/* let us see what is in our buffer */
printf("%s",buffer);

调试此代码显示“2\n”在测试代码部分覆盖缓冲区中的“1\n”(gcc 5.4.0 x64 GNU libc 版本:2.23)

输出为:

0
1
2
2

但我预计:

0
1
2
1
2

如有任何提示,我将不胜感激。

在关闭和打开 stdout、"dup"-ing、写入文件和读取文件以及其他奇怪的解决方案之后,我找到了一个适合我需要的解决方案,但不是那么便携但不是需要打开另一个文件:

How to buffer stdout in memory and write it from a dedicated thread

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_LEN 40

int main( int argc, char *argv[] ) {
  char buffer[MAX_LEN+1] = {0};
  int out_pipe[2];
  int saved_stdout;

  saved_stdout = dup(STDOUT_FILENO);  /* save stdout for display later */

  if( pipe(out_pipe) != 0 ) {          /* make a pipe */
    exit(1);
  }

  dup2(out_pipe[1], STDOUT_FILENO);   /* redirect stdout to the pipe */
  close(out_pipe[1]);

  /* anything sent to printf should now go down the pipe */
  printf("ceci n'est pas une pipe");
  fflush(stdout);

  read(out_pipe[0], buffer, MAX_LEN); /* read from pipe into buffer */

  dup2(saved_stdout, STDOUT_FILENO);  /* reconnect stdout for testing */
  printf("read: %s\n", buffer);

  return 0;
}

重写它以创建自己的模块后 "stdout_redirect.c" 结果是:

#define BIGENOUGH 1000
#define PIPE_READ   0
#define PIPE_WRITE  1

char stdout_buffer [BIGENOUGH];
static int stdout_save;
static int stdout_pipe[2];

bool stdout_redirect()
{
    stdout_save = dup(STDOUT_FILENO);  /* save stdout for display later */

    if( pipe(stdout_pipe) != 0 ) {          /* make a pipe */
        return false;
    }

    dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO);   /* redirect stdout to the pipe */
    close(stdout_pipe[PIPE_WRITE]);

    return true;
}

ssize_t stdout_restore()
{
    ssize_t size;
    fflush(stdout); /* flush if not flushed before */
    size = read(stdout_pipe[PIPE_READ], stdout_buffer, sizeof(stdout_buffer)); /* read from pipe into buffer */
    close(stdout_pipe[PIPE_READ]);
    dup2(stdout_save, STDOUT_FILENO);  /* reconnect stdout */
    return size;
}