自定义应用程序控制台和stderr

时间:2013-02-23 22:30:16

标签: c++

我正在编写一个类来从应用程序内部显示自定义控制台。我也使用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,所以我无法获取任何数据。

1 个答案:

答案 0 :(得分: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);

另请查看How do I read stdout/stderr output of a child process correctly?


对于任何想要将stdout重定向到Win32应用程序中的控制台窗口的人来说 的 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();

}

如果您希望控制台仅用于Debug,请确保包含<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

这是一个额外的小功能(它将消息记录到stderr stderr.log文件中)

void StdErr(char* Error) {

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

}