2

C言語を使用しています。stdout に書き込む関数があります。

その出力をキャプチャして、少し変更したいと思います(いくつかの文字列を置き換えます)。そして、それを標準出力に再度出力します。だから私はから始めたい:

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 */

問題は、huge_string_buffer を元の stdout に戻すにはどうすればよいかということです。

4

4 に答える 4

2

1 つのアイデアは、標準の Unix ユーティリティの機能を模倣することですが、tee外部のリダイレクトに依存することなく、プログラム内で完全に模倣することです。

だから私は簡単な関数を書いたmytee().これはうまくいくようだ. それは使用します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
   }
}

私のテストプログラムは次のとおりです。

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;
}

出力は次のとおりです。

<H><e><l><l><o>< ><W><o><r><l><d>
Captured: <Hello World>

アプリケーションでこれを使用するにmytee()は、テスト ステートメントprintf("<%c>", c)write(1, &c, 1). また、 への呼び出しでシグナルを処理する必要がある場合がありますread。そして、2 つdup2()のそれぞれの後に、次を追加することができます。

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

この種のリファレンスについては、たとえば、Dave Curry による27 年前の 220 ページの優れた短い O'Reillyの Unix システムでの C の使用を参照してください。

于 2012-06-27T00:31:42.840 に答える
1

これを行うUnixの方法は、実際には、必要な入力処理を行う小さなプログラムを作成し、その他のプログラムの出力をコマンドラインでパイプすることです。

すべてをCプログラムに保持することを主張する場合は、代わりにその関数を書き直して、出力を特定のcharバッファー(できれreturnばバッファーのchar *)に送信し、stdoutに送信したり処理したりできるようにします。クライアントが望むように。

たとえば、古い方法:

void usage () {
    printf ("usage: frob sourcefile [-options]\n");
}

...そして新しい方法:

char * usage(char * buffer) {
    strcpy (buffer, "usage: frob sourcefile [-options]\n");
    return buffer;
}
于 2012-06-26T19:34:00.973 に答える
0
char huge_string_buf[MASSIVE_SIZE];
FILE stdout_ori=fdopen(stdout,"a");
freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout);
setbuf(stdout, huge_string_buffer);
/* modify huge_string_buffer */
//Write to stdout_fdopen
于 2012-06-26T19:34:09.527 に答える
0

私はファイル記述子を使ったトリッキーなゲームは本当に好きではありません。stdoutに書き込む以外の方法でデータを返すように、関数を変更することはできませんか?

ソースコードにアクセスできず、それができない場合は、stdoutに書き込むコードを小さな別のプログラムに分割し、それを別のプロセスとして実行することをお勧めします。プロセスからの出力を(おそらく名前付きパイプを介して)リダイレクトするのは簡単でクリーンです。そうすれば、データを受信するプロセスからstdoutに出力することに問題はありません。

また、編集の種類によっては、Pythonなどの高級言語を使用してデータを編集した方がよい場合もあります。

于 2012-06-26T19:25:02.747 に答える