缓冲区处理stdout

时间:2016-09-06 17:38:02

标签: c redirect printf buffer stdout

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

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

我使用setvbuf重定向stdout以使用我自己指定的缓冲区。

我使用了流模式_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"在testcode部分的缓冲区中(gcc 5.4.0 x64 GNU libc version:2.23)

输出是:

0
1
2
2

但我期待:

0
1
2
1
2

我会感激任何提示。

1 个答案:

答案 0 :(得分:1)

在关闭和打开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;
}