【问题标题】:Custom application console and stderr自定义应用程序控制台和标准错误
【发布时间】:2013-02-23 22:30:15
【问题描述】:

我正在编写一个类来从应用程序内部显示自定义控制台。我还使用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:我尝试使用流 tee,但使用 stderr 而不是 std::cerr 的 glog 日志,所以我无法获取任何数据。

【问题讨论】:

  • listen to stderr 是什么意思?什么是 glog?
  • 我想捕获 stderr 输出并将其发送到我的控制台类,以便我可以在应用程序中呈现它。我说听是因为我不想重复轮询新数据,而只是在一些新消息被刷新时发送通知。
  • 那你就不需要自己的流了。转移 stderr 内容的 streambuf 就足够了。有关示例,请参见 Tee streams
  • 奥拉夫,非常感谢。我现在正在研究它,看起来正是我所需要的。

标签: c++


【解决方案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?


对于任何想要将标准输出重定向到 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();

}

如果您希望控制台仅用于调试,请确保包含 &lt;crtdbg.h&gt;,它定义了应用程序是否处于调试模式(对于 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);

}

【讨论】:

  • 我已经在使用它,但现在我正在尝试切换我的控制台类。标准控制台输出他自己的stderr和stdout,我要问的是如何为我的班级实现相同的。
  • 哦,很好。我想你解决了这个问题,然后使用 Olaf 建议的链接。
  • 虽然我不确定您到底想要什么(可能是我的错)...我的示例确实在输出发生时捕获了 stderr 并将其记录到控制台(stdin 样式)以及 cout ,和标准输出...如果我的例子没有帮助,请解释更多细节(也许还有图片),问题是什么(我道歉)。
  • 等待 -- 您是否尝试将 stderr 发送到控制台(内置于应用程序)和日志文件?
  • 当我在 glog 上记录某些内容时,它会将其附加到日志文件中,并通过 fprintf、fwrite 和 fflush 将其发送到 stderr。我想要做的是实例化我的控制台类并让它打印记录器发送到stderr的内容。我发现这个博客解释了如何实现类似的东西,但是该代码使用了 Windows 上不可用的库,我希望解决方案会更简单......zpasternack.blogspot.jp/2011/07/…
猜你喜欢
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多