收藏 分享(赏)

浅析ASSERT和TRACE宏附源代码(转).doc

上传人:HR专家 文档编号:6207754 上传时间:2019-04-02 格式:DOC 页数:12 大小:89.50KB
下载 相关 举报
浅析ASSERT和TRACE宏附源代码(转).doc_第1页
第1页 / 共12页
浅析ASSERT和TRACE宏附源代码(转).doc_第2页
第2页 / 共12页
浅析ASSERT和TRACE宏附源代码(转).doc_第3页
第3页 / 共12页
浅析ASSERT和TRACE宏附源代码(转).doc_第4页
第4页 / 共12页
浅析ASSERT和TRACE宏附源代码(转).doc_第5页
第5页 / 共12页
点击查看更多>>
资源描述

1、如果你没有用过甚至听过 ASSERT 或者 TRACE 调式宏,那么在很大程度上,你可以忽略这篇文章。不再扯不相关的东西,我们直入主题好了。1.TRACE1.1.TRACE 的宏定义同样的,我们先从 TRACE 的宏定义开始研究,TRACE 被定义在 AFX.H 中。但是我在这个H 文件查找时,并没有发现 TRACE 被#define 成某个函数。虽然你会发现类似的下面两行代码: #define TRACE _noop/#define TRACE ATLTRACE但是,ATL 的宏定义并不是我们要找的,而_noop,如果你翻过 MSDN 会发现这个 Keyword的作用仅仅是忽略被包含的函数及

2、不对参数进行评估(具体请看 A 附录)。那么, TRACE 到底是如何被使用的呢?机缘巧合之下(这个),我在 TRACE 的宏定义附近发现了下面的代码: inline void AFX_CDECL AfxTrace(.) / Look at here!#define TRACE _noop#define TRACE0(sz)#define TRACE1(sz, p1)#define TRACE2(sz, p1, p2)#define TRACE3(sz, p1, p2, p3)关注那个 AfxTrace。如果说我们前面找到的都不是真正的 TRACE 的话,那么,这个AfxTrace 就非常可能

3、是我们要找的,而且,他还是个 inline 函数!于是,我以“AfxTrace”为关键字 Google,果然找到了一些信息。在以前的 AFX.H 文件中,存在类似下面的代码: #ifdef _DEBUG void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, .); #define TRACE :AfxTrace #else #define TRACE 1 ? (void)0 : :AfxTrace #endif 很明显,我们可以看到,TRACE 被定义成了 AfxTrace。但是这里有个问题,为什么在我的VC2003 的 AFX.H 文件中,找不到这段代码呢?

4、看来需要高人回答哈1.2.AfxTrace既然 TRACE 宏只是调用了 AfxTrace,那么我们就来看看 AfxTrace 函数实现了什么。不过很可惜,AfxTrace 并不是一个文档记录函数(Documented-function),这意味着你在MSDN 是找不到他的相关信息,那么我们只能通过他的源代码来了解他的行为。AfxTrace 的源代码在 DUMPOUT.CPP 里。 void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, .)va_list args;va_start(args, lpszFormat);int nBuf;TCHAR szBuff

5、er512;nBuf = _vsntprintf(szBuffer, _countof(szBuffer), lpszFormat, args);/ was there an error? was the expanded string too long?ASSERT(nBuf = 0);afxDump this object, 1 = children objectsvoid SetDepth(int nNewDepth);/ OperationsCDumpContextOutputString(szBuffer);lpBuf = szBuffer;if (*lpsz = n)*lpBuf+

6、 = r;*lpBuf+ = *lpsz+;*lpBuf = 0;OutputString(szBuffer);return *this;m_pFile-Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR);return *this;做Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR);因为前面说过,m_pFile 的值为 NULL(我们没有给他传值,构造函数又自动给他 NULL 掉了),所以 OutputString 应该会执行下面的代码: / use C-runtime/OutputDebugString when m_pFile is

7、 NULLif (m_pFile = NULL)TRACE(traceDumpContext, 0, lpsz);return;很奇怪,很神奇,很囧又回到了 TRACE更何况,上面注释写着 use C-runtime/OutputDebugString 的字眼呢,多大个的字啊无奈中,我去翻了下 MSDN,又去 Google,结果得到了惊人的发现!在 MSDN,对于CDumpContext 有这么一段的描述: Under the Windows environment, the output from the predefined afxDump object, conceptually sim

8、ilar to the cerr stream, is routed to the debugger via the Windows function OutputDebugString. 换句话说,转储的东西的的确确会经过底层的 C 运行时库函数或者 OutputDebugString 这个 API。此时我想起了之前出现的一个关于 TRACE 的 BUG:在 UNICODE 下无法输出中文。当时我通过 F9/F10/F11 不断的跟进,但是单语句调试到 TRACE(traceDumpContext, 0, lpsz)这里时,却提示没有可显示的语句。所以,有可能转储的东西跑到了某个 C 底层函

9、数去(如果是 OutputDebugString,中文也应输出)。于是我把目光瞄准了 traceDumpContext,发现这个是个宏(很奇怪,是 ATL 系列的),经过多次进进出出的跟进后,发现了一个叫做 CTrace 的类,而且在里面还发现如下代码: class CTracepublic:typedef int (_cdecl *fnCrtDbgReport_t)(int,const char *,int,const char *,const char *,.);private:CTrace(#ifdef _ATL_NO_DEBUG_CRTfnCrtDbgReport_t pfnCrtDb

10、gReport = NULL)#elsefnCrtDbgReport_t pfnCrtDbgReport = _CrtDbgReport)#endif我很敏感的关注了_CtrDbgReport 这个函数,去 MSDN 翻了下,得到的结果很惊人! Generates a report with a debugging message and sends the report to three possible destinations (debug version only).而且,Remark 上还有这么一段(具体请参考附录): In Visual C+ 2005, _CrtDbgReport

11、W is the wide-character version of _CrtDbgReport. All its output and string parameters are in wide-character strings; otherwise it is identical to the single-byte character version. _CrtDbgReport and _CrtDbgReportW create the user message for the debug report by substituting the argumentn arguments

12、into the format string, using the same rules defined by the printf or wprintf functions. These functions then generate the debug report and determine the destination or destinations, based on the current report modes and file defined for reportType. When the report is sent to a debug message window,

13、 the filename, lineNumber, and moduleName are included in the information displayed in the window. 所以,我最后在假设的情况下得出了下列结论:OutputString 通过宏定义,最终转到了_CtrDbgReport 这个 C-Runtime 函数上,有他负责在底层的某个地方往输出框写调试信息。又因为我的 IDE 是 2003,所以_CtrDbgReport 只能输出 Single-byte Char,所以无法输出中文。如此,我们的浅析 TRACE 的部分应该算是圆满结束了-。-|2.ASSERT

14、看完了 TRACE,我们再来看看 ASSERT。相对来说,ASSERT 就比 TRACE 简单很多,所以我们不再分布叙述老规矩,还是先从宏定义开始入手。源代码在 AFX.H 中 #define ASSERT(f) (void) (f) | !AfxAssertFailedLine(THIS_FILE, _LINE_) | (AfxDebugBreak(), 0)比较简单,只有一行。不过不得不说的是,这句写得非常巧妙。你还记得|的运算顺序么?当 f 为 FALSE 的时候,会跳转到 AfxAssertFailedLine,这个函数的源代码在AFXASERT.CPP 中 BOOL AFXAPI A

15、fxAssertFailedLine(LPCSTR lpszFileName, int nLine)#ifndef _AFX_NO_DEBUG_CRT/ we remove WM_QUIT because if it is in the queue then the message box/ wont displayMSG msg;BOOL bQuit = PeekMessage(BOOL bResult = _CrtDbgReport(_CRT_ASSERT, lpszFileName, nLine, NULL, NULL);if (bQuit)PostQuitMessage(int)msg

16、.wParam);return bResult;#else/ Not supported.#error _AFX_NO_DEBUG_CRT is not supported.#endif / _AFX_NO_DEBUG_CRT首先, AfxAssertFailedLine 会阻塞所有活动的线程,然后显示我们非常熟悉也非常不愿意见到的消息框-_-!。这里也有一个_CtrDbgReport,个人猜测,那个消息框可能就是通过这个 C-Runtime 函数产生的。这个函数成功后会返回 TRUE,经过!运算后就变成了 FALSE,于是继续执行AfxDebugBreak。AfxDebugBreak 是一个

17、系列宏定义,源代码在 AFXVER_.H 中 #ifndef AfxDebugBreak#ifdef _AFX_NO_DEBUG_CRT/ by default, debug break is asm int 3, or a call to DebugBreak, or nothing#if defined(_M_IX86) & !defined(_AFX_PORTABLE)#define AfxDebugBreak() _asm int 3 #else#define AfxDebugBreak() DebugBreak()#endif#else#define AfxDebugBreak() _CrtDbgBreak()#endif#endif#ifndef _DEBUG#ifdef AfxDebugBreak#undef AfxDebugBreak#endif#define AfxDebugBreak()#endif / _DEBUG根据不同的环境使用不同的方式。不过他的表现行为还都是类似的,主要是把控制返回给VC 的调试器,这样一来,你就可以交互式的进行调式。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 学术论文 > 期刊/会议论文

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报