3

アプリケーション内からカスタム コンソールを表示するクラスを作成しています。glogまた、メッセージをファイルに記録すると同時に stderr に記録するためにも使用しています。コンソール クラスに stderr をリッスンさせるにはどうすればよいですか?

カスタム fstream を作成し、次のようなことを考えました。

CustomStream cs;
auto original_buf = std::cerr.rdbuf(cs.rdbuf());

stream operator <<コンソールクラスに送信されたものへの呼び出しがあります。

または、直接サブクラス化しstd::filebufて呼び出す:

CustomFilebuf fb;
auto original_buf = std::cerr.rdbuf(&fb);

これは正しい方法ですか?サンプルコードを検索しましたが、あまり見つかりませんでした。

Edit1: ストリーム ティーを使用してみましたが、 glog はstderrと ではなくログを記録するstd::cerrため、データを取得できませんでした。

4

1 に答える 1

1

これがあなたの質問に関連しているかどうかはわかりませんが...

ISO C99 は、7.19.5.3 のパラグラフ 6 で次のように述べています。

When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function [...], and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

また、stderrからの読み取りは「未定義の動作」であると言う人もいます...

stderr から読み取ることはできますが、読み取る前にフラッシュする限り:

fwrite("x", 1, 1, stderr);
fflush(stderr);
fgetc(stderr);

また、子プロセスの標準出力/標準エラー出力を正しく読み取るにはどうすればよいですか? もご覧ください。


Win32 アプリのコンソール ウィンドウに stdout をリダイレクトしたい人には、 AllocConsoleがあります。

stdout をコンソール ウィンドウにリダイレクトする単純な (自明な) 関数も作成しました。

#include <fstream>
#include <io.h>
#include <fcntl.h>

#define cMaxConsoleLines 500

void ReadyConsole() {

    short int hConHandle;
    long lStdHandle;

    CONSOLE_SCREEN_BUFFER_INFO coninfo;

    FILE *fp;

    // Allocate a console for the program
    AllocConsole();

    // set the screen buffer to be big enough to let us scroll text
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);

    coninfo.dwSize.Y = cMaxConsoleLines; // The max number of lines for the console!

    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);


    // Redirect STDOUT to the console
    lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen(hConHandle, "w");  // Writing to the console

    *stdout = *fp;

    setvbuf(stdout, NULL, _IONBF, 0);
    // -------------------------------


    // Redirect STDIN to the console
    lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen(hConHandle, "r");  // Reading from the console

    *stdin = *fp;

    setvbuf(stdin, NULL, _IONBF, 0);
    // ------------------------------


    // Redirect STDERR to the console
    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen(hConHandle, "w");  // STDERR writing to the console!

    *stderr = *fp;

    setvbuf(stderr, NULL, _IONBF, 0);
    // ------------------------------


    // Point the console to STDIO
    std::ios::sync_with_stdio();

}

コンソールをデバッグ専用にしたい場合は<crtdbg.h>、アプリがデバッグ モード (VC++ の場合) かどうかを定義する を必ず含めてください。たとえば、次のように追加できます。

#ifdef _DEBUG
// The file with the ReadyConsole function
#include <DebugStuff.h>
#endif

そしてそれを使用する

#ifdef _DEBUG
ReadyConsole(); // Ready the console for debugging
#endif

#ifdef _DEBUG
fprintf(stdout, "Position, Line 1, DEBUG-INFO-HERE");
cout << "COUT is working!"; // NOTE, for cout, you will need <iostream>
#endif

これは追加の小さな機能です (メッセージを stderrstderr.log ファイルの両方に記録します)。

void StdErr(char* Error) {

    fprintf(stderr, Error);
    FILE* FP = fopen("stderr.log", "a");
    fputs(Error, FP);
    fclose(FP);

}
于 2013-02-24T00:10:45.520 に答える