TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能;该宏仅仅在程序的DEBUG版本中出现,当RELEASE的时候该宏就完全消息了,从而帮助你调式也在RELEASE的时候减少代码量。
使用非常简单,格式如下:
TRACE("DDDDDDDDDDD");
TRACE("wewe%d",333);
同样还存在TRACE0,TRACE1,TRACE2。。。分别对应0,1,2。。个参数
TRACE信息输出到VC IDE环境的输出窗口(该窗口是你编译项目出错提示的哪个窗口),但仅限于你在VC中运行你的DEBUG版本的程序。
TRACE信息还可以使用DEBUGVIEW来捕获到。这种情况下,你不能在VC的IDE环境中运行你的程序,而将BUILD好的DEBUG版本的程序单独运行,这个时候可以在DEBUGVIEW的窗口看到DEBUGVIE格式的输出了。
------------------第二种方法------------------------------
OutputDebugString is a API function, it is used to help programmer debug the program, which is like
TRACE or afxDump, it is work with Dbgview. in Debug mode it performance as TRACE. But in Release mode
it can be monitor in DbgView.
OutputDebugString is explained in MSDN
The OutputDebugString function sends a string to the debugger for the current application.
VOID OutputDebugString(
LPCTSTR lpOutputString // pointer to string to be displayed
);
Parameters:
lpOutputString parameters Pointer to the null-terminated string to be displayed.
Return Values
This function does not return a value.
Remarks
If the application has no debugger, the system debugger displays the string.
If the application has no debugger and the system debugger is not active,
OutputDebugString does nothing.
Example:
void CSdfghfgView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
OutputDebugString("right button is pressed");
}
参数就是你需要输出的字符串了。如果你需要显示数字等,你需要事先格式化字符串。注意WINDOWS CE仅仅支持UNICODE版本,所以你提供的字符串应该转换为UNICODE。使用_tstrcat等来格式化字符串。
如果你的应用程序有一个DEBUGER,那么该函数输出到DEBUGER,否则就输出到系统的DEBUGER,如果两个都没有,该函数什么也不做。
注意,输出到系统DEBUGER的,你可以使用DEBUGVIEW工具查看日志,这样你在程序运行的时候也可以看到日志了。很多程序都使用这种方式来写日志,包括MICROSOFT本身也使用这种方法。
------------------第三种输出方法------------------------------------
当我们要在程序中输出调试信息时,常常以字符串的形式来输出,例如:
printf("Some debug information here!/n");
这段代码在Debug和Release版下都输出调试信息,这不是我们所要的,一般地大家都会添加
预编译指令,如下所示:
#if _DEBUG
printf("Some debug information here!/n");
#endif
这样就达到了在Debug版里程序输出调试信息,在Release版下不输出调试信息的目的。(在Release版里
连printf函数都没有调用)可如果要在程序里的许多地方输出调试信息,若采用上面的方式会很麻烦;
(至于为什么麻烦,可能就是不愿多敲几次键盘吧,呵呵。。。)
于是大家都想到写个输出函数,代码如下:
void printInfo(char *strInfo)
{
#if _DEBUG
printf(strInfo);
#endif
}注:该函数只是演示用的,很简单,没有其他检查字符串功能。
printInfo("Some debug information here!/n");确实,在Debug模式下运行该程序,则输出如下信息:
Some debug information here!
在Release模式下,则没输出什么信息;
我们往往在这个时候认为一切都OK了;如果你认为是,就没必要往下看了;呵呵。。。
虽然在Release版下运行程序没有输出调试信息来,可这些调试信息却留在了二进制的可执行文件里;
我们可以用IDA来打开该Release版的可执行文件,看到如图一所示的信息:
图一:IDA反汇编后的main函数
注:该函数就是main函数
可见调试信息字符串(“Some debug information here!/n”)确实存在于Release版的可执行文件里;
我们当然不希望别人看到这些调试信息,那有没有办法来防止该调试信息被编译进Release版的可执行文件里呢?
办法是有的,这里来描述2个方法。
办法一:
定义如下宏:
#if _DEBUG
#define _D(str) str
#else
#define _D(str) NULL
#endif
此时输出语句变为:printInfo(_D("Some debug information here!/n"));在Debug模式下运行程序,依然输出调试信息:
“Some debug information here!”;在Release下,则什么都不输出,此时我们用IDA看一下Release版的二进制文件,则没有发现该调试信息字符串。
#if _DEBUG
void printInfo(char *strInfo)
{
printf(strInfo);
}
#else
#define printInfo(str)
#endif注意:该宏把函数printInfo的定义也放进去了;
“Some debug information here!”;
在Release下,也什么都不输出,此时我们用IDA看一下Release版的二进制文件,也没有发现该调试信息字符串。
如图三示:
图三:IDA反汇编后的main函数
既然方法一和方法二都能实现同样的功能,那究竟那个方法好呢?
方法一和方法二确实都没在可执行文件里留下调试信息,比较一下图二和图三,我们不难发现:
图二当中多了一个函数调用 call nullsub_1,该函数就是printInfo,虽然该函数什么都不做,
但它却调用了,我们一般也不希望该函数调用,所以方法一中多了一个函数调用,增加了开销,
而方法二当中却没有调用该函数。
下面是程序源代码:
// 程序目的:
// 测试调试时输出的字符串信息
#include
//#define Method
#ifdef Method
//方法一
void printInfo(char *strInfo)
{
#if _DEBUG
printf(strInfo);
#endif
}
#if _DEBUG
#define _D(str) str
#else
#define _D(str) NULL
#endif
int main()
{
printInfo(_D("Some debug information here!/n"));
return 0;
}
#else
//方法二
#if _DEBUG
void printInfo(char *strInfo)
{
printf(strInfo);
}
#else
#define printInfo(str)
#endif
int main()
{
printInfo("Some debug information here!/n");
return 0;
}
#endif