将Cout重定向到Windows中的控制台

我有一个相对较旧的应用程序。通过一些小的更改,它几乎可以在Visual C ++ 2008中完美构建。我注意到的一件事是,我的“调试控制台”运行不正常。基本上,过去,我已经使用AllocConsole()过一个控制台,供调试输出使用。然后,我将使用freopen重定向stdout到它。这与C和C ++风格的IO完美配合。


现在,它似乎仅适用于C风格的IO。将类似的东西重定向cout到分配有控制台的正确方法是什么AllocConsole()?


这是曾经工作的代码:


if(AllocConsole()) {

    freopen("CONOUT$", "wt", stdout);

    SetConsoleTitle("Debug Console");

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);

}

编辑:发生在我身上的一件事是,我可以制作一个自定义streambuf,其溢出方法使用C风格的IO编写,并std::cout用它替换默认的流缓冲区。但这似乎是一个解决方案。有没有合适的方法在2008年做到这一点?还是MS忽略了这一点?


EDIT2:好的,所以我已经实现了上面阐述的想法。基本上看起来像这样:


class outbuf : public std::streambuf {

public:

    outbuf() {

        setp(0, 0);

    }


    virtual int_type overflow(int_type c = traits_type::eof()) {

        return fputc(c, stdout) == EOF ? traits_type::eof() : c;

    }

};


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {

    // create the console

    if(AllocConsole()) {

        freopen("CONOUT$", "w", stdout);

        SetConsoleTitle("Debug Console");

        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);  

    }


    // set std::cout to use my custom streambuf

    outbuf ob;

    std::streambuf *sb = std::cout.rdbuf(&ob);


    // do some work here


    // make sure to restore the original so we don't get a crash on close!

    std::cout.rdbuf(sb);

    return 0;

}

有没有人比强迫std::cout别人变得更好/更清洁的解决方案fputc?


跃然一笑
浏览 788回答 3
3回答

阿波罗的战车

这是解决此问题的函数的最新版本:void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr){&nbsp; &nbsp; // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been&nbsp; &nbsp; // observed that the file number of our standard handle file objects can be assigned internally to a value of -2&nbsp; &nbsp; // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our&nbsp; &nbsp; // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value&nbsp; &nbsp; // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to&nbsp; &nbsp; // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target&nbsp; &nbsp; // using the "_dup2" function.&nbsp; &nbsp; if (bindStdIn)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; FILE* dummyFile;&nbsp; &nbsp; &nbsp; &nbsp; freopen_s(&dummyFile, "nul", "r", stdin);&nbsp; &nbsp; }&nbsp; &nbsp; if (bindStdOut)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; FILE* dummyFile;&nbsp; &nbsp; &nbsp; &nbsp; freopen_s(&dummyFile, "nul", "w", stdout);&nbsp; &nbsp; }&nbsp; &nbsp; if (bindStdErr)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; FILE* dummyFile;&nbsp; &nbsp; &nbsp; &nbsp; freopen_s(&dummyFile, "nul", "w", stderr);&nbsp; &nbsp; }&nbsp; &nbsp; // Redirect unbuffered stdin from the current standard input handle&nbsp; &nbsp; if (bindStdIn)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);&nbsp; &nbsp; &nbsp; &nbsp; if(stdHandle != INVALID_HANDLE_VALUE)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(fileDescriptor != -1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FILE* file = _fdopen(fileDescriptor, "r");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(file != NULL)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int dup2Result = _dup2(_fileno(file), _fileno(stdin));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (dup2Result == 0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setvbuf(stdin, NULL, _IONBF, 0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Redirect unbuffered stdout to the current standard output handle&nbsp; &nbsp; if (bindStdOut)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);&nbsp; &nbsp; &nbsp; &nbsp; if(stdHandle != INVALID_HANDLE_VALUE)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(fileDescriptor != -1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FILE* file = _fdopen(fileDescriptor, "w");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(file != NULL)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int dup2Result = _dup2(_fileno(file), _fileno(stdout));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (dup2Result == 0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setvbuf(stdout, NULL, _IONBF, 0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Redirect unbuffered stderr to the current standard error handle&nbsp; &nbsp; if (bindStdErr)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);&nbsp; &nbsp; &nbsp; &nbsp; if(stdHandle != INVALID_HANDLE_VALUE)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(fileDescriptor != -1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FILE* file = _fdopen(fileDescriptor, "w");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(file != NULL)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int dup2Result = _dup2(_fileno(file), _fileno(stderr));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (dup2Result == 0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setvbuf(stderr, NULL, _IONBF, 0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the&nbsp; &nbsp; // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In&nbsp; &nbsp; // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything&nbsp; &nbsp; // has been read from or written to the targets or not.&nbsp; &nbsp; if (bindStdIn)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; std::wcin.clear();&nbsp; &nbsp; &nbsp; &nbsp; std::cin.clear();&nbsp; &nbsp; }&nbsp; &nbsp; if (bindStdOut)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; std::wcout.clear();&nbsp; &nbsp; &nbsp; &nbsp; std::cout.clear();&nbsp; &nbsp; }&nbsp; &nbsp; if (bindStdErr)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; std::wcerr.clear();&nbsp; &nbsp; &nbsp; &nbsp; std::cerr.clear();&nbsp; &nbsp; }}为了定义此功能,您需要以下一组包括:#include <windows.h>#include <io.h>#include <fcntl.h>#include <iostream>简而言之,该函数将C / C ++运行时标准输入/输出/错误句柄与与Win32进程关联的当前标准句柄同步。如文档中所述,AllocConsole为我们更改了这些过程句柄,因此所需要做的就是在AllocConsole之后调用该函数以更新运行时句柄,否则,我们将剩下初始化运行时时锁住的句柄。基本用法如下:// Allocate a console window for this processAllocConsole();// Update the C/C++ runtime standard input, output, and error targets to use the console windowBindCrtHandlesToStdHandles(true, true, true);此功能经过了多次修订,因此,如果您对历史信息或替代方法感兴趣,请检查对此答案的编辑。当前的答案是解决此问题的最佳方法,它具有最大的灵活性,并且可以在任何Visual Studio版本上使用。

Smart猫小萌

我以答案形式发布了一个便携式解决方案,因此可以接受。基本上我取代cout的streambuf与一个被用c文件实现的I / O,其不结束被重新定向。感谢大家的投入。class outbuf : public std::streambuf {public:&nbsp; &nbsp; outbuf() {&nbsp; &nbsp; &nbsp; &nbsp; setp(0, 0);&nbsp; &nbsp; }&nbsp; &nbsp; virtual int_type overflow(int_type c = traits_type::eof()) {&nbsp; &nbsp; &nbsp; &nbsp; return fputc(c, stdout) == EOF ? traits_type::eof() : c;&nbsp; &nbsp; }};int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {&nbsp; &nbsp; // create the console&nbsp; &nbsp; if(AllocConsole()) {&nbsp; &nbsp; &nbsp; &nbsp; freopen("CONOUT$", "w", stdout);&nbsp; &nbsp; &nbsp; &nbsp; SetConsoleTitle("Debug Console");&nbsp; &nbsp; &nbsp; &nbsp; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);&nbsp;&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; // set std::cout to use my custom streambuf&nbsp; &nbsp; outbuf ob;&nbsp; &nbsp; std::streambuf *sb = std::cout.rdbuf(&ob);&nbsp; &nbsp; // do some work here&nbsp; &nbsp; // make sure to restore the original so we don't get a crash on close!&nbsp; &nbsp; std::cout.rdbuf(sb);&nbsp; &nbsp; return 0;}
打开App,查看更多内容
随时随地看视频慕课网APP