一.前言:
一开始学习C++时,在控制台下写程序做练习,很容易输出程序变量,所以调试很方便。之后学习编写MFC程序,程序运行时要实时查看变量的情况就很麻烦了,虽然有TRACE宏(这个也是后来才知道的),但必须是程序结束后才能查看,而且阅读起来也很费劲。最开始自己写了个简陋的dis()函数(请看本文后面的附录),很简单,几行代码往程序一粘贴,再调用dis函数就可以显示字符串和int变量了。但后面输出的变量会覆盖之前的变量,所以还是不方便。于是一直在寻找一种输出变量更好的方法,偶然的情况下在网上下载了个DebugView.exe(下载),试了一下,就觉爱不释手。TRACE输出的变量实时地显示在DebugView上,给调试带来了更多的方便。本来以为是这已经是终极好方法,谁知又在偶然的情况下,看到一位高手写的一段代码,可以很简单的将变量输出到控制台窗口,比起用DebugView的方法是更甚一筹了。之后自己再做了些研究,不断改进,力求简单傻瓜,终于有了一个较为满意的解决法案了。现在拿出来很大家分享。希望对你有所帮助。
二.把trace函数添加到你的工程:
方法一:把下面的红色字体代码保存为头文件Trace.h,然后在StdAfx.h包含它。
方法二:直接把下面的红色字体代码粘贴在StdAfx.h中。(我个人更倾向于这种方法,方便)
#include <afxwin.h> // MFC core and standard components
/**************************************************************************** //如果想在Release版本中使用trace(),用"TRACE_WINDOW"代替"#ifdef _DEBUG"中的"_DEBUG" #define IndexLength 6 //设置序号的长度 #ifdef _DEBUG #include <sstream> //设置类成为通用版本 class DEBUG_WINDOW ~DEBUG_WINDOW() { fclose(fp); } void PrintString(TCHAR* OutputStr,int nMax) void SetWindowPos(HWND hWndInsertAfter=HWND_TOPMOST,int x=0,int y=0,int cx=200,int cy=200) template<class T> void Trace(TCHAR* ArgName,T a) //实例化一个对象,要定义为static,否则通不过编译 static int DebugItemIndex=0; #define SetDebugWndPos(X,Y,Z,W,T) {DebugWnd.SetWindowPos(X,Y,Z,W,T);} #define trace(X) { AddIndex();DebugWnd.Trace(TEXT(#X),X); DebugWnd.PrintString(_T("/n"),1); }
//{{AFX_INSERT_LOCATION}} #endif // !defined(AFX_STDAFX_H__EE32DF26_4082_4291_A7C6_3A35739DAD97__INCLUDED_) |
三.使用示例
void CDemoDlg::OnButton1()
{
int a=45; trace(a); //输出int型
double b=67.45; trace(b); //输出double型
TCHAR buf[20]=_T("jacky"); trace(buf); //输出字符串
trace("测试");
trace(_T("测试"));
}
void CDemoDlg::OnButton2()
{
int a=45; double b=67.45;
trace2(a,b);
}
void CDemoDlg::OnButton3()
{
POINT point;
GetCursorPos(&point);
TracePoint(point);
}
void CDemoDlg::OnButton4()
{
RECT rect;
::GetWindowRect(m_hWnd,&rect);
TraceRect(rect);
}
void CDemoDlg::OnButton5()
{
TraceLastError();
}
四.几点说明
1.输出函数有以下几个:
trace(X) //输出1个变量
trace2(X,Y) //输出2个变量
trace3(X,Y,Z) //输出3个变量
trace4(X,Y,Z,W) //输出4个变量
TracePoint(P) //输出坐标型POINT的数据
TraceRect(X) //输出RECT型的数据
TraceLastError()//输出上次错误的代码号
2.几个trace函数都具有自动识别数据类型的功能。
如:
int a=45; trace(a); //输出int型
char str[10]="jacky"; trace(str); //输出字符串
double b=67.45; trace(b); //输出double型
3.用trace()函数直接输出字符串时,可以不添加_T() 或 TEXT() 宏
trace("my test");
trace(_T("my test"));
trace(TEXT("my test"));
以上三个函数输出的都是 “my test”;
4.设置输出窗口的位置和大小。
在OnInitDialog()里添加下面代码:
SetDebugWndPos(HWND_TOPMOST,0,0,400,600);
5.如果想在Release版本中使用trace(),请用"TRACE_WINDOW"代替"#ifdef _DEBUG"中的"_DEBUG"就可以了
6.上面的代码支持Unicode,在VC6和VS2008中编译通过
五.图片预览
六.示例代码下载
trace_Demo.zip (在VC6下编译通过,支持unicode)(请不要直接使用迅雷下载)
trace_Demo_for_VS2008 (在vs2008中编译通过,支持unicode)
七.写应用程序日志
以下这个ftrace() 函数跟上面提到的trace() 函数的用法非常相似,不同点:
1.trace()监视的变量会显示在窗口并且保存在"DebugData.txt"文件中,
而ftrace() 直接保存变量在AppLog.txt中。
2.ftrace()是以追加的方式存入到原有的文件,而trace()每次都会删除原来
DebugData.txt中的数据后再重新保存
3.用法和上面描述的一样,把下面的代码粘贴在StdAfx.h中
/**************************************************************************** //注释掉这一句会使所有ftrace()函数无效 #ifdef WRITE_DATA #include <sstream> //设置类成为通用版本 class WRITE_DATA_TO_FILE void PrintString(TCHAR* OutputStr,int nMax) //实例化一个对象 #else |
八.另一个监视变量的工具
它是高手Paul DiLascia写的,相信会很不错。
http://www.dilascia.com/TraceWin.htm
其他:
vc 调试信息输出
文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/20090303/157190.html
1.CDumpContext
该类没有基类。
这个类支持面向流的诊断输出,以人能够阅读的文本。
该类重载了<<操作符。
afxDump是一个预声明的CDumpContext对象,可以方便使用。
该对象只在MFC的Debug版中有效。
可以将调式信息输出到调试输出窗口或调试终端。
// example for afxDump
CPerson myPerson = new CPerson;
// set some fields of the CPerson object...
//..
// now dump the contents
#ifdef _DEBUG
afxDump << "Dumping myPerson:/n";
myPerson->Dump( afxDump );
afxDump << "/n";
#endif
如果想建立一个制定的输出,比如一个制定的errlog文件。
我们可以自己生成一个CDumpContext对象。
方法如下:
CFile f;
if( !f.Open( "dump.txt", CFile::modeCreate | CFile::modeWrite ) ) {
afxDump << "Unable to open file" << "/n";
exit( 1 );
}
CDumpContext dc( &f );
2.TRACE
这个宏可以在DEBUG过程中,方便的跟踪程序中的变量的值。
在Debug环境中,TRACE宏输出到afxDump对象中。
在Release环境中,它不起作用。
TRACE一次限制512个字符,包括结束的NULL字符。
如果超过将引发ASSERT。
例:
int i = 1;
char sz[] = "one";
TRACE( "Integer = %d, String = %s/n", i, sz );
// Output: 'Integer = 1, String = one'
同时,还有TRACE0,TRACE1,TRACE2,TRACE3等宏。
数字代表宏中的参数数。
// example for TRACE0
TRACE0( "Start Dump of MyClass members:" );
// example for TRACE1
int i = 1;
TRACE1( "Integer = %d/n", i );
// Output: 'Integer = 1'
// example for TRACE2
int i = 1;
char sz[] = "one";
TRACE2( "Integer = %d, String = %s/n", i, sz );
// Output: 'Integer = 1, String = one'
3.void AfxDump( const CObject* pOb )
该函数调用对象的Dump成员函数,将信息输出到afxDump制定的位置。
最好不要在程序中调用该函数,而使用对象的Dump函数。
4.virtual void Dump( CDumpContext& dc ) const;
是CObjec的成员函数,将对象的内容输出到一个CDumpContext对象。
写自定义类的时候,应该重写Dump函数,来提供诊断服务。
重写的Dump函数中一般会先调用基类的Dump函数,后输出数据成员。
CObject::Dump输出类名,如果你的类用了IMPLEMENT_DYNAMIC或IMPLEMENT_SERIAL宏。
例:
class CPerson : public CObject
{
public:
//声明
#ifdef _DEBUG
virtual void Dump( CDumpContext& dc ) const;
#endif
CString m_firstName;
CString m_lastName;
// etc. ...
};
//实现
#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
// call base class function first
CObject::Dump( dc );
// now do the stuff for our specific class
dc << "last name: " << m_lastName << "/n"
<< "first name: " << m_firstName << "/n";
}
#endif
//调用
CPerson person;
#ifdef _DEBUG
CFile f;
if( !f.Open( "c://dump.txt", CFile::modeCreate | CFile::modeWrite ) ) {
afxDump << "Unable to open file" << "/n";
exit( 1 );
}
CDumpContext dc( &f );
person.Dump(dc);
dc<<"test dump output";
#endif
在较复杂的程序中,我们可以采用上述方法,
在调试程序的过程中,输出自己想要的数据和信息。
还是较为方便和简单的方法的。
文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/20090303/157190.html