使用输出流进行调试






4.84/5 (14投票s)
如何创建写入调试终端的输出流
背景
调试程序的方法有很多种(是的,我知道 - 从一开始就写出正确的代码),但无论你喜欢什么工具,使用 printf
方法通常非常方便。好吧,既然你是一位现代 C++ 程序员,你可能并不真正想要 printf
,而是想要使用一个输出流,比如 cerr
。
但只有一个问题,你正在编写 Windows 应用程序,所以没有标准的错误输出可以写入。实际上并非如此,确实有,而且你可能已经多次使用过它。当你使用 TRACE
宏之一时,结果会出现在 Visual Studio 的调试窗格中。MFC 会尽力在发布版本中关闭所有这些调试输出,但保留它通常非常方便。
当然,你不会在发布版本中从 Visual Studio 看到任何输出,但有其他程序可以捕获此输出。一个不错的选择是 DebugView,来自 www.sysinternals.com。顺便说一下,如果你启动这个程序,你可能会看到来自 Internet Explorer 的大约一百万条消息。你看,即使是微软也在练习发布版本调试!
问题
那么,如何将标准输出流定向到调试终端?一般来说,正确的答案是继承自 streambuf
并将新类连接到正常的 ostream
。这样,所有流插入器和操纵符都能按预期工作。在这种情况下,我们可以通过继承自 stringbuf
来节省一些工作。所以,无需赘述,以下是如何操作。
代码
首先,我们包含所需的头文件。
#include <Windows.h>
#include <ostream>
#include <sstream>
#include <string>
现在开始实际工作:由于我们正在使用 stringbuf
,我们只需要重写 sync
函数。
sync
方法实际上是将 put 区域中的文本传输到 streambuf
使用的任何输出目标,在本例中通过调用 API 函数 OutputDebugString
。
template <class CharT, class TraitsT = std::char_traits<CharT> >
class basic_debugbuf :
public std::basic_stringbuf<CharT, TraitsT>
{
public:
virtual ~basic_debugbuf()
{
sync();
}
protected:
int sync()
{
output_debug_string(str().c_str());
str(std::basic_string<CharT>()); // Clear the string buffer
return 0;
}
void output_debug_string(const CharT *text) {}
};
接下来,我专门化输出例程,使其根据需要调用 Ansi 或 Unicode API。
template<>
void basic_debugbuf<char>::output_debug_string(const char *text)
{
::OutputDebugStringA(text);
}
template<>
void basic_debugbuf<wchar_t>::output_debug_string(const wchar_t *text)
{
::OutputDebugStringW(text);
}
这基本上就是你所需要的,但为了方便起见,我还提供了一个从 basic_ostream
派生的类,该类将输出流连接到刚刚创建的 basic_debugbuf
。
为了像 cout
一样工作,你应该创建一个类型为 dostream
或 wdostream
的全局对象,并使用它进行输出。
template<class CharT, class TraitsT = std::char_traits<CharT> >
class basic_dostream :
public std::basic_ostream<CharT, TraitsT>
{
public:
basic_dostream() : std::basic_ostream<CharT, TraitsT>
(new basic_debugbuf<CharT, TraitsT>()) {}
~basic_dostream()
{
delete rdbuf();
}
};
typedef basic_dostream<char> dostream;
typedef basic_dostream<wchar_t> wdostream;
历史
- 2001年4月18日 - 原始版本
- 2001年11月23日 - 更新为使用 Jim Barry 建议的
stringbuf
。
同时修复了剩余的 HTML 标记错误,这些错误导致代码无法编译