本文介绍了将标准输出捕获到字符串并将其输出回 C 中的标准输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述

使用C语言.我有一个写入标准输出的函数.

我想捕获该输出,稍微修改一下(替换一些字符串).然后再次将其输出到标准输出.所以我想开始:

char huge_string_buf[MASSIVE_SIZE];freopen("NUL", "a", 标准输出);-或- freopen("/dev/null", "a", stdout);setbuf(标准输出,巨大的字符串缓冲区);/* 修改巨大的字符串缓冲区 */

现在的问题是,如何将巨大的字符串缓冲区输出回原来的标准输出?

解决方案

一个想法是模仿标准 Unix 实用程序 tee 的功能,但要完全在您的程序中这样做,而不依赖于外部重定向.

所以我写了一个简单的函数,mytee(),它似乎可以工作.它使用 shmget()、pipe()、fork() 和 dup2():

#include #include #include #include 静态字符 *mytee(整数大小){int shmid = shmget(IPC_PRIVATE, size + 1, 0660 | IPC_CREAT);int pipe_fds[2];管道(pipe_fds);开关(叉())​​{case -1://= 错误错误(叉");退出(EXIT_FAILURE);案例 0: {//= 孩子char *out = shmat(shmid, 0, 0), c;int i = 0;出[0] = 0;dup2(pipe_fds[0], 0);//将管道重定向到孩子的标准输入setvbuf(stdout, 0, _IONBF, 0);while (read(0, &c, 1) == 1 && i ", c);//将父级的标准输出传递给真正的标准输出,出[i++] = c;//然后在 mycapture 缓冲区中缓冲出[i] = 0;//(额外的 <> 只是为了清楚起见)}_退出(退出_成功);}默认值://= 父级dup2(pipe_fds[1], 1);//用输出替换 stdout 到 childsetvbuf(stdout, 0, _IONBF, 0);返回 shmat(shmid, 0, 0);//返回孩子的捕获缓冲区}}

我的测试程序是:

int main(void) {char *mycapture = mytee(100);//捕获前 100 个字节printf("你好世界");//示例测试字符串睡眠(1);fprintf(stderr, "\nCaptured: \n", mycapture);返回0;}

输出为:

要在您的应用程序中使用它,在 mytee() 中,您需要将测试语句 printf("<%c>", c) 替换为只需 write(1, &c, 1).并且您可能需要在对 read 的调用中处理信号.在两个 dup2() 之后,您可能需要添加:

 close(pipe_fds[0]);关闭(pipe_fds[1]);

有关此类内容的参考,请参阅例如优秀而简短的 27 岁的 220 页 O'Reilly 书籍在 Unix 系统上使用 C,作者为 Dave Curry.

C language is used. I have a function that writes to stdout.

I would like to capture that output, modify it a bit (replacing some strings). And than output it again to the stdout. So I want to start with:

char huge_string_buf[MASSIVE_SIZE];
freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout);
setbuf(stdout, huge_string_buffer);
/* modify huge_string_buffer */

The question is now, how do I output the huge_string_buffer back to the original stdout?

解决方案

One idea is to mimic the functionality of the standard Unix utility tee, but to do so entirely within your program, without relying on outside redirection.

So I've written a simple function, mytee(), which seems to work. It uses shmget(), pipe(), fork(), and dup2():

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>

static char *mytee(int size) {
   int shmid = shmget(IPC_PRIVATE, size + 1, 0660 | IPC_CREAT);
   int pipe_fds[2];
   pipe(pipe_fds);

   switch (fork()) {
      case -1:                      // = error
         perror("fork");
         exit(EXIT_FAILURE);
      case 0: {                     // = child
         char *out = shmat(shmid, 0, 0), c;
         int i = 0;
         out[0] = 0;
         dup2(pipe_fds[0], 0);      // redirect pipe to child's stdin
         setvbuf(stdout, 0, _IONBF, 0);
         while (read(0, &c, 1) == 1 && i < size) {
            printf("<%c>", c);      // pass parent's stdout to real stdout,
            out[i++] = c;           // and then buffer in mycapture buffer
            out[i] = 0;             // (the extra <> are just for clarity)
         }
         _exit(EXIT_SUCCESS);
      }
      default:                      // = parent
         dup2(pipe_fds[1], 1);      // replace stdout with output to child
         setvbuf(stdout, 0, _IONBF, 0);
         return shmat(shmid, 0, 0); // return the child's capture buffer
   }
}

My test program is:

int main(void) {
   char *mycapture = mytee(100);    // capture first 100 bytes
   printf("Hello World");           // sample test string
   sleep(1);
   fprintf(stderr, "\nCaptured: <%s>\n", mycapture);
   return 0;
}

The output is:

To use this in your application, in mytee() you'll need to replace the test statement printf("<%c>", c) with just write(1, &c, 1). And you may need to handle signals in the call to read. And after each of the two dup2()'s, you may want to add:

  close(pipe_fds[0]);
  close(pipe_fds[1]);

For a reference on this sort of stuff, see for example the excellent and short 27-year-old 220-page O'Reilly book Using C on the Unix System by Dave Curry.

这篇关于将标准输出捕获到字符串并将其输出回 C 中的标准输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 10:45