Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

Visual C++でデバッグ時の出力をIDE(Visual Studio)上に出す方法

スポンサードリンク

f:id:fa11enprince:20200628231119j:plain
Visual Studioの出力ウィンドウまたはイミディエイトウィンドウに
なにか文字列を出力したい時は
コンソールアプリケーション、Windowsアプリケーションに
関わらず、OutputDebugString()を使うとそれが実現できます。
使い方はputs()と同様です。改行はつけなきゃダメですが。
printf()と同じ使い勝手のものも作りました。
いつ使うんだよvsprintf()。今でしょ。
https://msdn.microsoft.com/ja-jp/library/cc428973.aspx
イメージはこんな感じです。

やりたいことのイメージ

f:id:fa11enprince:20150704192133p:plain
はい、これでできましたね。めでたしめでたし……

で終わるのはアレなので、
もし、C++のcout/wcoutで使いたいときはどうすればよいかというと、
出力を乗っ取ればよいのです。
wcout版だとこうなります。

wcoutの出力を乗っ取る

class DbgStreambufW : public std::wstreambuf
{
public:
    // Put character on overflow
    virtual int_type overflow(int_type c = EOF) override
    {
        if (c != EOF)
        {
            wchar_t buf[] = { c, '\0' };
            OutputDebugString(buf);
        }
        return c;
    }
};

class DbgOutW
{
private:
    DbgStreambufW dstm;
    std::wstreambuf *def_stm;
public:
    DbgOutW()
    {
        def_stm = std::wcout.rdbuf(&dstm);
    }
    ~DbgOutW()
    {
        std::wcout.rdbuf(def_stm);
    }
};

これで利用時にwcoutをいつも通り使って、
デバッグ実行*1をすると、
イミディエイトウィンドウか出力ウィンドウに出力されます。
このどちらかは設定によります。
デバッグ > オプションと設定 >
 出力文字ウィンドウの全てをイミディエイトウィンドウにリダイレクトする
にチェックが入っていればイミディエイトウィンドウに出ます。
f:id:fa11enprince:20150704192059p:plain

あとVisual Studio 2012あたりから内部処理で使う文字セットの
デフォルトがUnicodeになっていますので、
Visual C++だとUnicode用でコーディングするのがいいのでしょうかね……
面倒だけど。
設定場所はここです。
f:id:fa11enprince:20150704192433p:plain

そんなわけでサンプル用のコードを書きました。

サンプルコード

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <locale.h>
#include <tchar.h>
#include <stdlib.h>
#include <iostream>
#include <windows.h>

class DbgStreambufW : public std::wstreambuf
{
public:
    // Put character on overflow
    virtual int_type overflow(int_type c = EOF) override
    {
        if (c != EOF)
        {
            wchar_t buf[] = { c, '\0' };
            OutputDebugString(buf);
        }
        return c;
    }
};

class DbgOutW
{
private:
    DbgStreambufW dstm;
    std::wstreambuf *def_stm;
public:
    DbgOutW()
    {
        def_stm = std::wcout.rdbuf(&dstm);
    }
    ~DbgOutW()
    {
        std::wcout.rdbuf(def_stm);
    }
};

// OutputDebugStringをprintfと同じ使い勝手にする
void printf_ex(LPCTSTR pszFormat, ...)
{
    va_list	argp;
    TCHAR pszBuf[256];
    va_start(argp, pszFormat);
    // 第2引数に注意 変な名前ですが、vsprintfです。
    _vstprintf(pszBuf, sizeof(pszBuf), pszFormat, argp);
    va_end(argp);
    OutputDebugString(pszBuf);
}

int main()
{
    _tsetlocale(LC_ALL, _T(""));
    int i = 10;
    int j = 20;
    // デバッグして実行じゃないと出ない。
    // イミディエイトウィンドウにでるかそうでないかは
    // デバッグ > オプションと設定 > 出力文字ウィンドウの全て… 
    printf_ex(_T("下の出力ウィンドウに出す。\n"));
    printf_ex(_T("i : %d, j : %d\n"), i, j);
    OutputDebugString(_T("aaa\n"));

    // C++ wcoutの場合
    // cout版用意していないですがまぁ、いらないよね……
    {
        DbgOutW o;
        using namespace std;
        // Lを付け忘れると悲惨です。
        wcout << L"とりあえず出力\n";
    }
    return 0;
}

そうそう、最初のキャプチャはC版専用で作っていたのでtest.c
となっていますが、こちらはC++用なんでtest.cppで作ってくださいね。
setlocaleとか謎めいてますよね。
_tsetlocaleをつかっときゃいいのかとりあえず……。
いろいろバリエーションあってどれ使えばいいんだと。

今日のメモ終わり(*´Д`)

*1:デバッグなしで開始では出力されない