1

と の両方を同じ出力ファイルdup2にリダイレクトしようとすると、問題が発生します。stdoutstderr

この説明用のコード サンプルを使用しています: (gcc 4.8.2、Ubuntu 14.04)

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define USE2FILES

int main()
{
    int f1, f2, status;

    f1 = open("test.out", O_CREAT | O_WRONLY, 0644);
    if (f1 == -1) {
        perror("open(): ");
    }
    status = dup2(f1, STDOUT_FILENO);
    if (status == -1) {
        perror("dup2(): ");
    }

#ifdef USE2FILES
    close(f1);
#endif

#ifdef USE2FILES
    f2 = open("test.out", O_CREAT | O_WRONLY, 0644);
    if (f2 == -1) {
        perror("dup2(): ");
    }
#else
    f2 = f1;
#endif
    status = dup2(f2, STDERR_FILENO);
    if (status == -1) {
        perror("dup2(): ");
    }
    close(f2);

    fprintf(stderr, "test_stderr1\n");
    fprintf(stdout, "test_stdout1\n");
    fprintf(stderr, "test_stderr2\n");
    fprintf(stdout, "test_stdout2\n");
    fprintf(stderr, "test_stderr3\n");
    fprintf(stdout, "test_stdout3\n");

    fflush(stdout);
    fflush(stderr);

    return 0;
}

USE2FILES マクロは、stdoutと にそれぞれ複製される 2 つのファイル記述子 (同じファイルへの) を使用するか、とのstderr両方に複製される 1 つのファイル記述子を使用するかを切り替えることになっています。stdoutstderr

リダイレクトに 2 つの異なるファイル記述子を使用するとうまくいくはずだという印象を受けました。ただし、このコードを USE2FILES on で実行すると、次の出力が に出力されtest.outます。

test_stdout1
test_stdout2
test_stdout3

次に USE2FILES を無効にすると、次のようになります。

test_stderr1
test_stderr2
test_stderr3
test_stdout1
test_stdout2
test_stdout3

最初のケースでは出力stderrが通過しないようです。この動作は予期されるものですか (何か不足していますか)?

編集:クリス・ドッドの答えを受け入れた後:それは確かに悪い例です。fprintfシーケンスを次のように変更します。

    fprintf(stderr, "test_stderr+++++++++++++++++++++++++++++++++++++++++++++++++1\n");
    fprintf(stdout, "test_stdout----------------------------------------1\n");
    fprintf(stderr, "test_stderr++++++++++++++++++++++++++++++++++2\n");
    fprintf(stdout, "test_stdout----------------2\n");
    fprintf(stderr, "test_stderr++++++++++++++++++++++++++++3\n");
    fprintf(stdout, "test_stdout----------------------3\n");

test.outこの出力を取得します:

test_stdout----------------------------------------1
test_stdout----------------2
test_stdout----------------------3
err++++++++++++++++++++++++++++3

かなりはっきりstdoutと表示stderrされ、同じファイルに対する書き込みと競合しています。

4

1 に答える 1

5

2 つのopen呼び出しを行うと、それぞれ独自の I/O カーソル (ファイル オフセット) を持つ 2 つの異なるカーネル ファイルハンドルを取得するため、2 つのファイル記述子への書き込みは互いに上書きします。単一のopen呼び出しを使用すると、両方のファイル記述子が参照する単一のファイルハンドルのみが取得されるため、(各記述子への) 書き込みごとに出力オフセットが進められるため、次の書き込み (他のファイル記述子による) はその後に書き込みます。

あなたの例では、書き込まれた文字列はまったく同じ長さであるため、への書き込みは前の書き込みをstdout正確に上書きしますstderr。ファイルの書き込みはFILE、(必ずしも)fprintfが呼び出されたときではなく、オブジェクトがフラッシュされたときにのみ発生することに注意してください。

モードでファイルを開くことによって、得ようとしていると思われる効果を得ることもできO_APPENDます。これにより、すべての書き込みで、実際に書き込む直前に書き込みオフセットがファイルの現在の末尾に再配置されます。

于 2014-07-16T21:20:10.803 に答える