亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

將Cout重定向到Windows中的控制臺

將Cout重定向到Windows中的控制臺

C++
躍然一笑 2019-11-29 10:32:27
我有一個相對較舊的應用程序。通過一些小的更改,它幾乎可以在Visual C ++ 2008中完美構建。我注意到的一件事是,我的“調試控制臺”運行不正常?;旧希^去,我已經使用AllocConsole()過一個控制臺,供調試輸出使用。然后,我將使用freopen重定向stdout到它。這與C和C ++風格的IO完美配合?,F在,它似乎僅適用于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?
查看完整描述

3 回答

?
阿波羅的戰車

TA貢獻1862條經驗 獲得超6個贊

這是解決此問題的函數的最新版本:


void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)

{

    // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been

    // observed that the file number of our standard handle file objects can be assigned internally to a value of -2

    // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our

    // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value

    // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to

    // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target

    // using the "_dup2" function.

    if (bindStdIn)

    {

        FILE* dummyFile;

        freopen_s(&dummyFile, "nul", "r", stdin);

    }

    if (bindStdOut)

    {

        FILE* dummyFile;

        freopen_s(&dummyFile, "nul", "w", stdout);

    }

    if (bindStdErr)

    {

        FILE* dummyFile;

        freopen_s(&dummyFile, "nul", "w", stderr);

    }


    // Redirect unbuffered stdin from the current standard input handle

    if (bindStdIn)

    {

        HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);

        if(stdHandle != INVALID_HANDLE_VALUE)

        {

            int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);

            if(fileDescriptor != -1)

            {

                FILE* file = _fdopen(fileDescriptor, "r");

                if(file != NULL)

                {

                    int dup2Result = _dup2(_fileno(file), _fileno(stdin));

                    if (dup2Result == 0)

                    {

                        setvbuf(stdin, NULL, _IONBF, 0);

                    }

                }

            }

        }

    }


    // Redirect unbuffered stdout to the current standard output handle

    if (bindStdOut)

    {

        HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);

        if(stdHandle != INVALID_HANDLE_VALUE)

        {

            int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);

            if(fileDescriptor != -1)

            {

                FILE* file = _fdopen(fileDescriptor, "w");

                if(file != NULL)

                {

                    int dup2Result = _dup2(_fileno(file), _fileno(stdout));

                    if (dup2Result == 0)

                    {

                        setvbuf(stdout, NULL, _IONBF, 0);

                    }

                }

            }

        }

    }


    // Redirect unbuffered stderr to the current standard error handle

    if (bindStdErr)

    {

        HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);

        if(stdHandle != INVALID_HANDLE_VALUE)

        {

            int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);

            if(fileDescriptor != -1)

            {

                FILE* file = _fdopen(fileDescriptor, "w");

                if(file != NULL)

                {

                    int dup2Result = _dup2(_fileno(file), _fileno(stderr));

                    if (dup2Result == 0)

                    {

                        setvbuf(stderr, NULL, _IONBF, 0);

                    }

                }

            }

        }

    }


    // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the

    // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In

    // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything

    // has been read from or written to the targets or not.

    if (bindStdIn)

    {

        std::wcin.clear();

        std::cin.clear();

    }

    if (bindStdOut)

    {

        std::wcout.clear();

        std::cout.clear();

    }

    if (bindStdErr)

    {

        std::wcerr.clear();

        std::cerr.clear();

    }

}

為了定義此功能,您需要以下一組包括:


#include <windows.h>

#include <io.h>

#include <fcntl.h>

#include <iostream>

簡而言之,該函數將C / C ++運行時標準輸入/輸出/錯誤句柄與與Win32進程關聯的當前標準句柄同步。如文檔中所述,AllocConsole為我們更改了這些過程句柄,因此所需要做的就是在AllocConsole之后調用該函數以更新運行時句柄,否則,我們將剩下初始化運行時時鎖住的句柄?;居梅ㄈ缦拢?/p>


// Allocate a console window for this process

AllocConsole();


// Update the C/C++ runtime standard input, output, and error targets to use the console window

BindCrtHandlesToStdHandles(true, true, true);

此功能經過了多次修訂,因此,如果您對歷史信息或替代方法感興趣,請檢查對此答案的編輯。當前的答案是解決此問題的最佳方法,它具有最大的靈活性,并且可以在任何Visual Studio版本上使用。


查看完整回答
反對 回復 2019-11-29
?
Smart貓小萌

TA貢獻1911條經驗 獲得超7個贊

我以答案形式發布了一個便攜式解決方案,因此可以接受。基本上我取代cout的streambuf與一個被用c文件實現的I / O,其不結束被重新定向。感謝大家的投入。


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;

}

查看完整回答
反對 回復 2019-11-29
  • 3 回答
  • 0 關注
  • 859 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號