浅析ASSERT和TRACE宏附源代码转Word下载.docx
- 文档编号:21610685
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:10
- 大小:22.56KB
浅析ASSERT和TRACE宏附源代码转Word下载.docx
《浅析ASSERT和TRACE宏附源代码转Word下载.docx》由会员分享,可在线阅读,更多相关《浅析ASSERT和TRACE宏附源代码转Word下载.docx(10页珍藏版)》请在冰豆网上搜索。
#ifdef
_DEBUG
void
AFX_CDECL
AfxTrace(LPCTSTR
lpszFormat,
...);
#define
TRACE
:
:
AfxTrace
#else
1
?
(void)0
#endif
很明显,我们可以看到,TRACE被定义成了AfxTrace。
但是这里有个问题,为什么在我的VC2003的AFX.H文件中,找不到这段代码呢?
看来需要高人回答哈~
1.2.AfxTrace
既然TRACE宏只是调用了AfxTrace,那么我们就来看看AfxTrace函数实现了什么。
不过很可惜,AfxTrace并不是一个文档记录函数(Documented-function),这意味着你在MSDN是找不到他的相关信息,那么我们只能通过他的源代码来了解他的行为。
AfxTrace的源代码在DUMPOUT.CPP里。
voidAFX_CDECLAfxTrace(LPCTSTRlpszFormat,...)
{
va_listargs;
va_start(args,lpszFormat);
intnBuf;
TCHARszBuffer[512];
nBuf=_vsntprintf(szBuffer,_countof(szBuffer),lpszFormat,args);
//wasthereanerror?
wastheexpandedstringtoolong?
ASSERT(nBuf>
=0);
afxDump<
<
szBuffer;
va_end(args);
}
首先我们来看三个东西:
这一组宏主要是用来解决函数的不定参数的。
回想一下,我们可以在TRACE中输出任意个参数,靠的就是这三个东西。
因为C没有重载函数,更何况即使有,当函数参数个数不确定时,重载的局限性就显得非常大,于是就有人想通过利用指针参数解决了这个问题。
由于这个东西比较复杂(MS足够再写一篇专门的文章了),所以在此不作详细阐述,有兴趣的可以参考下列URL:
1.MSDN:
2.
接着我们可以看到,AfxTrace声明了大小为512的TCHAR数组作为缓冲区,然后用_vsntprintf往缓冲区里写已经格式化好的数据。
而_vsntprintf系列函数专门用于以va_list处理可变参数的函数输出。
具体请参考附录
最后,AfxTrace又用afxDump对szBuffer进行转储(似乎就是输出到输出框)。
看来,我们还需要对afxDump函数进行跟进。
1.3.afxDump
afxDump是一个CDumpContext类的预定义对象,用于在Debug模式下,往VC的输出窗口输出调试信息。
很幸运,M$在MSDN中记录了他的一些信息。
(具体请参考附录)
所以,一般的,当存在如下代码时:
LPCTSTRlpszKC=L"
KCisaFucker"
;
lpszKC;
输出框便会输出“KCisafucker”。
我们现在来看看afxDump的定义代码。
源代码在AFX.H中
#ifdef_DEBUG
externAFX_DATACDumpContextafxDump;
//LookAtHere!
externAFX_DATABOOLafxTraceEnabled;
//这个变量和afxTraceFlags同为调式输出的开关标志
//不过MS在新版本的MFC中被废除了
#endif
然后我们再来看看CDumpContext辅助类的定义。
源代码同样也在AFX.H中
classCDumpContext
public:
CDumpContext(CFile*pFile=NULL);
//Attributes
intGetDepth()const;
//0=>
thisobject,1=>
childrenobjects
voidSetDepth(intnNewDepth);
//Operations
CDumpContext&
operator<
(LPCTSTRlpsz);
#ifdef_UNICODE
(LPCSTRlpsz);
//automaticallywidened
#else
(LPCWSTRlpsz);
//automaticallythinned
(constvoid*lp);
(constCObject*pOb);
(constCObject&
ob);
(BYTEby);
(WORDw);
DumpAsHex(BYTEb);
DumpAsHex(WORDw);
#ifdef_WIN64
(LONGl);
(DWORDdw);
(intn);
(UINTu);
DumpAsHex(LONGl);
DumpAsHex(DWORDdw);
DumpAsHex(intn);
DumpAsHex(UINTu);
(LONG_PTRl);
(DWORD_PTRdw);
(INT_PTRn);
(UINT_PTRu);
DumpAsHex(LONG_PTRl);
DumpAsHex(DWORD_PTRdw);
DumpAsHex(INT_PTRn);
DumpAsHex(UINT_PTRu);
(floatf);
(doubled);
(LONGLONGn);
(ULONGLONGn);
DumpAsHex(LONGLONGn);
DumpAsHex(ULONGLONGn);
(HWNDh);
(HDCh);
(HMENUh);
(HACCELh);
(HFONTh);
voidHexDump(LPCTSTRlpszLine,BYTE*pby,intnBytes,intnWidth);
voidFlush();
//Implementation
protected:
//dumpcontextobjectscannotbecopiedorassigned
CDumpContext(constCDumpContext&
dcSrc);
voidoperator=(constCDumpContext&
voidOutputString(LPCTSTRlpsz);
intm_nDepth;
CFile*m_pFile;
};
CDumpContext只有一个构造函数,而且默认把m_pFile设置成了NULL,这点很关键,我们在后面马上会看到~
这里可能会有点疑问,为什么会存在一个CFile*类型的Public成员变量?
我也不知道,KC个人的猜测是,CDumpContext不仅能够往输出框输出信息,应该还能够往外写文件。
而下面的m_pFile->
Write也能够支持我的猜测。
另一个亮点是,CDumpContext中存在多个<
重载运算符,这样便于afxDump进行不同类型的<
运算。
不过这里有一个插曲,CDumpContext的上述代码中有几行比较有意思:
之前我一直不明白这段的用意,后来经D大提醒,幡然醒悟。
这段宏的作用大致是:
在UNICODE下,遇到MBCS字符串自动做扩大处理;
在MBCS下,遇到UNICODE字符串自动做缩小处理。
相应的实现代码如下:
//specialversionforANSIcharacters
CDumpContext:
operator<
(LPCSTRlpsz)
if(lpsz==NULL)
OutputString(L"
(NULL)"
);
return*this;
//limitedlength
_mbstowcsz(szBuffer,lpsz,_countof(szBuffer));
szBuffer[511]=0;
return*this<
//_UNICODE
//specialversionforWIDEcharacters
(LPCWSTRlpsz)
OutputString("
charszBuffer[512];
_wcstombsz(szBuffer,lpsz,_countof(szBuffer));
#endif
//!
_UNICODE
/////////////////////////////////////////////////////////////////////////////
接下来我们重点看CDumpContext对<
的实现。
虽然<
的重载很多,但是从本质上,可以分成对String和数值类型的两类。
那么我们先来看看对于数值类型的处理,额,随便挑一个~当~当~当~当~
(WORDw)
TCHARszBuffer[32];
wsprintf(szBuffer,_T("
%u"
),(UINT)w);
OutputString(szBuffer);
return*this;
因为是数值类型,所以算上64Bit的大整数,也长不到哪里去。
所以这里分配的缓冲区数组的下标只有32.
然后利用wsprintf把数字格式化,最后用OutputString输出。
wsprintf详细信息请参考附录
至于对String的处理,代码如下:
(LPCTSTRlpsz)
OutputString(_T("
NULL"
));
ASSERT(lpsz!
=NULL);
if(lpsz==NULL)
AfxThrowUserException();
if(m_pFile==NULL)
TCHARszBuffer[512];
LPTSTRlpBuf=szBuffer;
while(*lpsz!
='
\0'
)
{
if(lpBuf>
szBuffer+_countof(szBuffer)-3)
*lpBuf='
lpBuf=szBuffer;
if(*lpsz=='
\n'
*lpBuf++='
\r'
*lpBuf++=*lpsz++;
}
*lpBuf='
OutputString(szBuffer);
m_pFile->
Write(lpsz,lstrlen(lpsz)*sizeof(TCHAR));
做<
前,先对参数进行合法性检查,然后在m_pFile为NULL的情况下,分配缓冲区(由于是字符串,所以下标为512),然后逐一的复制字符,最后相同的用OutputString转出。
比较上面两种<
的运算实现,我们可以很明显的看出,最后的数据都被传递到了OutputString里,所以我们还必须跟进OutputString。
1.4.OutputString
我们现在跳到OutputString的实现源代码上:
voidCDumpContext:
OutputString(LPCTSTRlpsz)
//useC-runtime/OutputDebugStringwhenm_pFileisNULL
TRACE(traceDumpContext,0,lpsz);
return;
//otherwise,writethestringtothefile
因为前面说过,m_pFile的值为NULL(我们没有给他传值,构造函数又自动给他NULL掉了),所以OutputString应该会执行下面的代码:
很奇怪,很神奇,很……囧……又回到了TRACE……
更何况,上面注释写着useC-runtime/OutputDebugString的字眼呢,多大个的字啊……
无奈中,我去翻了下MSDN,又去Google,结果得到了惊人的发现!
在MSDN,对于CDumpContext有这么一段的描述:
UndertheWindowsenvironment,theoutputfromthepredefinedafxDumpobject,conceptuallysimilartothecerrstream,isroutedtothedebuggerviatheWindowsfunctionOutputDebugString.
换句话说,转储的东西的的确确会经过底层的C运行时库函数或者OutputDebugString这个API。
此时我想起了之前出现的一个关于TRACE的BUG:
在UNICODE下无法输出中文。
当时我通过F9/F10/F11不断的跟进,但是单语句调试到TRACE(traceDumpContext,0,lpsz)这里时,却提示没有可显示的语句。
所以,有可能转储的东西跑到了某个C底层函数去(如果是OutputDebugString,中文也应输出)。
于是我把目光瞄准了traceDumpContext,发现这个是个宏(很奇怪,是ATL系列的),经过多次进进出出的跟进后,发现了一个叫做CTrace的类,而且在里面还发现如下代码:
classCTrace
typedefint(__cdecl*fnCrtDbgReport_t)(int,constchar*,int,constchar*,constchar*,...);
private:
CTrace(
#ifdef_ATL_NO_DEBUG_CRT
fnCrtDbgReport_tpfnCrtDbgReport=NULL)
fnCrtDbgReport_tpfnCrtDbgReport=_CrtDbgReport)
我很敏感的关注了_CtrDbgReport这个函数,去MSDN翻了下,得到的结果很惊人!
Generatesareportwithadebuggingmessageandsendsthereporttothreepossibledestinations(debugversiononly).
而且,Remark上还有这么一段(具体请参考附录):
InVisualC++2005,_CrtDbgReportWisthewide-characterversionof_CrtDbgReport.Allitsoutputandstringparametersareinwide-characterstrings;
otherwiseitisidenticaltothesingle-bytecharacterversion.
_CrtDbgReportand_CrtDbgReportWcreatetheusermessageforthedebugreportbysubstitutingtheargument[n]argumentsintotheformatstring,usingthesamerulesdefinedbytheprintforwprintffunctions.Thesefunctionsthengeneratethedebugreportanddeterminethedestinationordestinations,basedonthecurrentreportmodesandfiledefinedforreportType.Whenth
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 浅析 ASSERT TRACE 源代码