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

这是正确的方法吗?我搜索了一些示例代码,但找不到很多。

stderrEdit1:我尝试使用流三通,但使用和不使用 glog 日志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);

另请查看如何正确读取子进程的 stdout/stderr 输出?


对于想要将标准输出重定向到 Win32 应用程序中的控制台窗口的任何人,都有 AllocConsole

我什至创建了一个简单的(微不足道的)函数来将标准输出重定向到控制台窗口:

#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 回答