诊断服务
Microsoft 基础类库提供了很多简化调试程序的诊断服务。 这些诊断服务包括宏和全局函数,让你能够跟踪程序的内存分配,在运行时转储对象的内容并打印调试消息。 诊断服务的宏和全局函数可分为以下几类:
常规诊断宏
常规诊断函数和变量
对象诊断函数
这些宏和函数可用于派生自 MFC 调试和发布版本中的 CObject
的所有类。 但是,除 DEBUG_NEW 和 VERIFY 之外,它们在发布版本中不执行任何操作。
在调试库中,所有分配的内存块被一系列的“保护字节”包围。如果这些字节受到错误内存写入的干扰,诊断例程可以报告问题。 如果包括行:
#define new DEBUG_NEW
在实现文件中,所有对 new
的调用将存储发生内存分配的文件名和行号。 函数 CMemoryState::DumpAllObjectsSince 将显示此附加信息,帮助你确定内存泄漏。 关于诊断输出的其他信息,另请参阅 CDumpContext 类。
此外,C 运行时库还支持一组可用于调试应用程序的诊断函数。 有关详细信息,请参阅《运行时库参考》中的 调试例程 。
MFC 常规诊断宏
名称 | 描述 |
---|---|
ASSERT | 如果库调试版本中的指定表达式的计算结果为 FALSE ,则打印一条消息,然后中止程序。 |
ASSERT_KINDOF | 测试对象是指定类的对象还是指定类派生类的对象。 |
ASSERT_VALID | 通过调用 AssertValid 成员函数测试一个对象的内部有效性;通常从 CObject 中重写。 |
DEBUG_NEW | 提供调试模式下用于所有对象分配的文件名和行号以帮助查找内存泄漏。 |
DEBUG_ONLY | 类似于 ASSERT 但不会测试表达式的值;对仅在调试模式下执行的代码非常有用。 |
ENSURE 和 ENSURE_VALID | 用于验证数据正确性。 |
THIS_FILE | 展开到正在编译的文件的名称。 |
TRACE | 在库调试版本中提供类似 printf 的功能。 |
VERIFY | 类似于 ASSERT ,但是可在库发布版本以及调试版本中计算表达式的值。 |
MFC 常规诊断变量和函数
名称 | 描述 |
---|---|
afxDump | 将 CDumpContext 信息发送给调试器输出窗口或调试终端的全局变量。 |
afxMemDF | 控制调试内存分配器行为的全局变量。 |
AfxCheckError | 用于测试传递的 SCODE 是否出错的全局变量,如果出错,将引发相应的错误。 |
AfxCheckMemory | 检查所有当前分配的内存的完整性。 |
AfxDebugBreak | 导致执行中断。 |
AfxDump | 如果在调试器中调用,将在调试时转储对象的状态。 |
AfxDump | 在调试时转储对象状态的内部函数。 |
AfxDumpStack | 生成当前堆栈的映像。 此函数始终以静态方式链接。 |
AfxEnableMemoryLeakDump | 启用内存泄漏转储。 |
AfxEnableMemoryTracking | 打开和关闭内存跟踪。 |
AfxIsMemoryBlock | 验证内存块是否正确分配。 |
AfxIsValidAddress | 验证内存地址范围是否在程序边界内。 |
AfxIsValidString | 确定一个字符串指针是否有效。 |
AfxSetAllocHook | 实现每次内存分配的函数调用。 |
MFC 对象诊断函数
名称 | 描述 |
---|---|
AfxDoForAllClasses | 对支持运行时类型检查的所有 CObject 派生类执行指定函数。 |
AfxDoForAllObjects | 对使用 new 分配的所有 CObject 派生对象执行指定函数。 |
MFC 编译宏
名称 | 描述 |
---|---|
_AFX_SECURE_NO_WARNINGS | 取消显示有关对已弃用的 MFC 函数的使用的编译器警告。 |
_AFX_SECURE_NO_WARNINGS
取消显示有关对已弃用的 MFC 函数的使用的编译器警告。
语法
_AFX_SECURE_NO_WARNINGS
示例
如果未定义 _AFX_SECURE_NO_WARNINGS
,则此代码示例将产生一个编译器警告。
// define this before including any afx files in *pch.h* (*stdafx.h* in Visual Studio 2017 and earlier)
#define _AFX_SECURE_NO_WARNINGS
// . . .
CRichEditCtrl* pRichEdit = new CRichEditCtrl;
pRichEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,
CRect(10,10,100,200), pParentWnd, 1);
char sz[256];
pRichEdit->GetSelText(sz);
AfxDebugBreak
调用此函数,导致在执行 MFC 应用程序的调试版本时中断(在调用 AfxDebugBreak
的位置处)。
语法
void AfxDebugBreak( );
备注
AfxDebugBreak
在 MFC 应用程序的发布版本中不起作用,应将其删除。 此函数只应在 MFC 应用程序中使用。 使用 Win32 API 版本 DebugBreak
导致非 MFC 应用程序中断。
要求
标头:afxver_.h
ASSERT
计算其参数。
ASSERT(booleanExpression)
参数
booleanExpression
指定计算结果不为零或为零的表达式(包括指针值)。
备注
如果结果为 0,则宏将打印诊断消息并中止程序。 如果条件为非零,则不执行任何操作。
诊断消息具有以下形式
assertion failed in file <name> in line <num>
其中,name 是源文件的名称,num 是源文件中失败的断言的行号。
在 MFC 的发布版本中,ASSERT 不计算表达式,因此不会中断程序。 如果必须计算表达式而不考虑环境,请使用 VERIFY 宏代替 ASSERT。
注意
此函数仅在 MFC 的调试版本中可用。
示例
CAge* pcage = new CAge(21); // CAge is derived from CObject.
ASSERT(pcage != NULL);
ASSERT(pcage->IsKindOf(RUNTIME_CLASS(CAge)));
// Terminates program only if pcage is NOT a CAge*.
要求
标头: afx.h
ASSERT_KINDOF
此宏断言所指向的对象是指定类的对象还是指定类派生类的对象。
ASSERT_KINDOF(classname, pobject)
参数
classname
CObject
派生类的名称。
pobject
指向类对象的指针。
备注
pobject 参数应是指向对象的指针,可以是 const
。 所指向的对象和类必须支持 CObject
运行时类信息。 例如,若要确保 pDocument
是指向 CMyDoc
类的对象或其任何派生对象的指针,可以进行编码:
ASSERT_KINDOF(CMyDoc, pDocument);
使用 ASSERT_KINDOF
宏与编码完全相同:
ASSERT(pDocument->IsKindOf(RUNTIME_CLASS(CMyDoc)));
此函数仅适用于使用 [DECLARE_DYNAMIC](run-time-object-model-services.md#declare_dynamic 或 DECLARE_SERIAL 宏声明的类。
注意
此函数仅在 MFC 的调试版本中可用。
要求
标头: afx.h
ASSERT_VALID
用于测试有关对象内部状态有效性的假设。
ASSERT_VALID(pObject)
参数
pObject
指定派生自 CObject
的类的对象,该类具有 AssertValid
成员函数的重写版本。
注解
ASSERT_VALID 调用作为参数传递的对象的 AssertValid
成员函数。
在 MFC 的发布版本中,ASSERT_VALID 不执行任何操作。 在调试版本中,会验证指针、检查其值是否为 NULL 并调用对象自己的 AssertValid
成员函数。 如果其中任何测试失败,则会以与 ASSERT 相同的方式显示警报消息。
注意
此函数仅在 MFC 的调试版本中可用。
有关详细信息和示例,请参阅调试 MFC 应用程序。
示例
// Assure that pMyObject is a valid pointer to an
// object derived from CObject.
ASSERT_VALID(pMyObject);
要求
标头: afx.h
DEBUG_NEW
有助于查找内存泄漏。
#define new DEBUG_NEW
备注
可以在程序中的所有位置使用 DEBUG_NEW,通常使用 new
运算符来分配堆存储。
在调试模式下(定义 _DEBUG 符号时),DEBUG_NEW 跟踪它分配的每个对象的文件名和行号。 然后,使用 CMemoryState::DumpAllObjectsSince 成员函数时,使用 DEBUG_NEW 分配的每个对象都使用分配所在的文件名和行号显示。
若要使用 DEBUG_NEW,请将以下指令插入源文件:
#define new DEBUG_NEW
插入此指令后,预处理器将插入使用 new
的 DEBUG_NEW,MFC 会执行其余操作。 编译程序的发布版本时,DEBUG_NEW 将解析为简单的 new
操作,并且不会生成文件名和行号信息。
注意
在早期版本的 MFC(4.1 及更早版本)中,需要将 #define
语句置于调用 IMPLEMENT_DYNCREATE or IMPLEMENT_SERIAL 宏的所有语句之后。 现在已没有必要。
要求
标头: afx.h
DEBUG_ONLY
在调试模式下(定义 _DEBUG 符号时),DEBUG_ONLY 计算其参数。
DEBUG_ONLY(expression)
备注
在发布生成中,DEBUG_ONLY 不计算其参数。 当有应仅在调试生成中执行的代码时,这非常有用。
DEBUG_ONLY 宏等同于周围包含 #ifdef _DEBUG
和 #endif
的表达式。
示例
void ExampleFunc(char* p, int size, char fill)
{
char* q; // working copy of pointer
VERIFY(q = p); // copy buffer pointer and validate
ASSERT(size >= 100); // make sure buffer is at least 100 bytes
ASSERT(isalpha(fill)); // make sure fill character is alphabetic
// if fill character is invalid, substitute 'X' so we can continue
// debugging after the preceding ASSERT fails.
DEBUG_ONLY(fill = (isalpha(fill)) ? fill : 'X');
}
要求
标头: afx.h
ENSURE 和 ENSURE_VALID
用于验证数据正确性。
语法
ENSURE( booleanExpression )
ENSURE_VALID( booleanExpression )
参数
booleanExpression
指定要测试的布尔表达式。
备注
这些宏的目的是改进参数的验证。 宏可防止进一步处理代码中的错误参数。 与 ASSERT 宏不同,除了生成断言外,ENSURE 宏还会引发异常。
根据项目配置,宏的行为有两种方式。 宏调用 ASSERT,如果断言失败,则引发异常。 因此,在调试配置(即,定义 _DEBUG 的位置)中,宏生成断言和异常,而在发布配置中,宏仅生成异常(ASSERT 不会在发布配置中计算表达式)。
宏 ENSURE_ARG 的行为类似于 ENSURE 宏。
ENSURE_VALID 调用 ASSERT_VALID 宏(该宏仅在调试生成中生效)。 此外,如果指针为 NULL,则 ENSURE_VALID 将引发异常。 NULL 测试在调试和发布配置中执行。
如果其中任何测试失败,则会以与 ASSERT 相同的方式显示警报消息。 如果需要,宏将引发无效的参数异常。
要求
标头: afx.h
THIS_FILE
展开到正在编译的文件的名称。
语法
THIS_FILE
备注
该信息由 ASSERT 和 VERIFY 宏使用。 应用程序向导和代码向导会将宏置于它们创建的源代码文件中。
示例
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// __FILE__ is one of the six predefined ANSI C macros that the
// compiler recognizes.
要求
标头: afx.h
TRACE
将指定的字符串发送到当前应用程序的调试器。
TRACE(exp)
TRACE(DWORD category, UINT level, LPCSTR lpszFormat, ...)
备注
有关 TRACE 的说明,请参阅 ATLTRACE2。 TRACE 和 ATLTRACE2 具有相同的行为。
在 MFC 的调试版本中,此宏将指定的字符串发送到当前应用程序的调试器。 在发布生成中,此宏不会编译为任何代码(根本不会生成任何代码)。
有关详细信息,请参阅调试 MFC 应用程序。
要求
标头: afx.h
VERIFY
在 MFC 的调试版本中,计算其参数。
VERIFY(booleanExpression)
参数
booleanExpression
指定计算结果不为零或为零的表达式(包括指针值)。
备注
如果结果为 0,则宏将打印诊断消息并停止程序。 如果条件为非零,则不执行任何操作。
诊断消息具有以下形式
assertion failed in file <name> in line <num>
其中,name 是源文件的名称,num 是源文件中失败的断言的行号。
在 MFC 的发布版本中,VERIFY 会计算表达式,但不会打印或中断程序。 例如,如果表达式是函数调用,则将进行调用。
示例
// VERIFY can be used for things that should never fail, though
// you may want to make sure you can provide better error recovery
// if the error can actually cause a crash in a production system.
// It _is_ possible that GetDC() may fail, but the out-of-memory
// condition that causes it isn't likely. For a test application,
// this use of VERIFY() is fine. For any production code, this
// usage is dubious.
// get the display device context
HDC hdc;
VERIFY((hdc = ::GetDC(hwnd)) != NULL);
// give the display context back
::ReleaseDC(hwnd, hdc);
要求
标头: afx.h
afxDump (CDumpContext in MFC)
在应用程序中提供基本对象转储功能。
CDumpContext afxDump;
注解
afxDump
是预定义的 CDumpContext 对象,该对象可用于将 CDumpContext
信息发送到调试器输出窗口或调试终端。 通常,将 afxDump
作为参数提供给 CObject::Dump
。
在 Windows NT 和所有版本的 Windows 下,调试应用程序时,afxDump
输出将发送到 Visual C++ 的输出调试窗口。
此变量仅在 MFC 的调试版本中定义。 有关 afxDump
的详细信息,请参阅调试 MFC 应用程序。
示例
// example for afxDump
CPerson* pMyPerson = new CPerson;
// set some fields of the CPerson object...
//..
// now dump the contents
#ifdef _DEBUG
afxDump << _T("Dumping myPerson:\n");
pMyPerson->Dump(afxDump);
afxDump << _T("\n");
#endif
要求
标头: afx.h
AfxDump(内部)
MFC 用于在调试时转储对象状态的内部函数。
语法
void AfxDump(const CObject* pOb);
参数
pOb
指向派生自 CObject
的类的对象的指针。
备注
AfxDump
调用对象的 Dump
成员函数,并将信息发送到 afxDump
变量指定的位置。 AfxDump
仅在 MFC 的调试版本中可用。
程序代码不应调用 AfxDump
,但应改为调用相应对象的 Dump
成员函数。
要求
标头: afx.h
afxMemDF
可以从调试器或程序访问此变量,并允许优化分配诊断。
int afxMemDF;
备注
afxMemDF
可以具有下列值(由枚举 afxMemDF
所指定):
allocMemDF
打开调试分配器(调试库中的默认设置)。delayFreeMemDF
延迟释放内存。 当程序释放内存块时,分配器不会将该内存返回到基础操作系统。 这将对程序施加最大内存压力。checkAlwaysMemDF
每次分配或释放内存时均调用AfxCheckMemory
。 这将显著降低内存分配和解除分配速度。
示例
afxMemDF = allocMemDF | checkAlwaysMemDF;
要求
标头: afx.h
AfxCheckError
此函数将测试传递的 SCODE 以查看它是否是错误。
void AFXAPI AfxCheckError(SCODE sc);
throw CMemoryException*
throw COleException*
备注
如果为错误,则此函数将引发异常。 如果传递的 SCODE 为 E_OUTOFMEMORY,则此函数将通过调用 AfxThrowMemoryException 引发 CMemoryException。 否则,此函数将通过调用 AfxThrowOleException 引发 COleException。
此函数可用于检查调用应用程序中的 OLE 函数返回的值。 通过在你的应用程序中使用此函数测试返回值,你可使用最少的代码正确反映错误条件。
注意
此函数的效果与调试生成和不调试生成的相同。
示例
AfxCheckError(::CoCreateInstance(clsidWMP, NULL, CLSCTX_INPROC_SERVER,
IID_IDispatch, (LPVOID*)& pWMPDispatch));
oddWMP.AttachDispatch(pWMPDispatch, TRUE);
要求
标头: afx.h
AfxCheckMemory
此函数验证可用内存池,并根据需要打印错误消息。
BOOL AfxCheckMemory();
返回值
如果没有内存错误,则为非零;否则为 0。
备注
如果函数未检测到内存损坏,则不会打印任何内容。
检查当前在堆上分配的所有内存块,包括由 new
分配的内存块,但不包括通过直接调用基础内存分配器来分配的内存块(如 malloc 函数或 GlobalAlloc
Windows 函数)。 如果发现任何块已损坏,则会在调试器输出中打印消息。
如果在程序模块中包括行,
#define new DEBUG_NEW
则对 AfxCheckMemory
的后续调用将显示分配内存的文件名和行号。
注意
如果模块包含可序列化类的一个或多个实现,则必须在最后一个 IMPLEMENT_SERIAL 宏调用之后放置 #define
行。
此函数仅适用于 MFC 的调试版本。
示例
CAge* pcage = new CAge(21); // CAge is derived from CObject.
Age* page = new Age(22); // Age is NOT derived from CObject.
*(((char*)pcage) - 1) = 99; // Corrupt preceding guard byte
*(((char*)page) - 1) = 99; // Corrupt preceding guard byte
AfxCheckMemory();
要求
标头: afx.h
AfxDump (MFC)
在调试器中调用此函数以在调试时转储对象的状态。
void AfxDump(const CObject* pOb);
参数
pOb
指向派生自 CObject
的类的对象的指针。
备注
AfxDump
调用对象的 Dump
成员函数,并将信息发送到 afxDump
变量指定的位置。 AfxDump
仅在 MFC 的调试版本中可用。
程序代码不应调用 AfxDump
,但应改为调用相应对象的 Dump
成员函数。
要求
标头: afx.h
AfxDumpStack
此全局函数可用于生成当前堆栈的图像。
void AFXAPI AfxDumpStack(DWORD dwTarget = AFX_STACK_DUMP_TARGET_DEFAULT);
参数
dwTarget
指示转储输出的目标。 可以使用按位 OR (|
) 运算符进行组合的可能值如下所示:
AFX_STACK_DUMP_TARGET_TRACE 通过 TRACE 宏发送输出。 TRACE 宏仅在调试生成中生成输出;它在发布生成中不生成任何输出。 此外,还可以将 TRACE 重定向到调试器以外的其他目标。
AFX_STACK_DUMP_TARGET_DEFAULT 将转储输出发送到默认目标。 对于调试生成,输出将转到 TRACE 宏。 在发布生成中,输出将转到剪贴板。
AFX_STACK_DUMP_TARGET_CLIPBOARD 仅将输出发送到剪贴板。 使用 CF_TEXT 剪贴板格式将数据作为纯文本放置在剪贴板上。
AFX_STACK_DUMP_TARGET_BOTH 同时将输出发送到剪贴板和 TRACE 宏。
AFX_STACK_DUMP_TARGET_ODS 通过 Win32 函数
OutputDebugString()
将输出直接发送到调试器。 当调试器附加到进程时,此选项将在调试生成和发布生成中生成调试器输出。 AFX_STACK_DUMP_TARGET_ODS 始终连接到调试器(如果已连接)且无法重定向。
备注
下面的示例反映了从 MFC 对话框应用程序中的按钮处理程序调用 AfxDumpStack
生成的单行输出:
=== begin AfxDumpStack output ===
00427D55: DUMP2\DEBUG\DUMP2.EXE! void AfxDumpStack(unsigned long) + 181 bytes
0040160B: DUMP2\DEBUG\DUMP2.EXE! void CDump2Dlg::OnClipboard(void) + 14 bytes
0044F884: DUMP2\DEBUG\DUMP2.EXE! int _AfxDispatchCmdMsg(class CCmdTarget *,
unsigned int,int,void ( CCmdTarget::*)(void),void *,unsigned int,struct
AFX_CMDHANDLE
0044FF7B: DUMP2\DEBUG\DUMP2.EXE! virtual int CCmdTarget::OnCmdMsg(unsigned
int,int,void *,struct AFX_CMDHANDLERINFO *) + 626 bytes
00450C71: DUMP2\DEBUG\DUMP2.EXE! virtual int CDialog::OnCmdMsg(unsigned
int,int,void *,struct AFX_CMDHANDLERINFO *) + 36 bytes
00455B27: DUMP2\DEBUG\DUMP2.EXE! virtual int CWnd::OnCommand(unsigned
int,long) + 312 bytes
00454D3D: DUMP2\DEBUG\DUMP2.EXE! virtual int CWnd::OnWndMsg(unsigned
int,unsigned int,long,long *) + 83 bytes
00454CC0: DUMP2\DEBUG\DUMP2.EXE! virtual long CWnd::WindowProc(unsigned
int,unsigned int,long) + 46 bytes
004528D9: DUMP2\DEBUG\DUMP2.EXE! long AfxCallWndProc(class CWnd *,struct
HWND__ *,unsigned int,unsigned int,long) + 237 bytes
00452D34: DUMP2\DEBUG\DUMP2.EXE! long AfxWndProc(struct HWND__ *,unsigned
int,unsigned int,long) + 129 bytes
BFF73663: WINDOWS\SYSTEM\KERNEL32.DLL! ThunkConnect32 + 2148 bytes
BFF928E0: WINDOWS\SYSTEM\KERNEL32.DLL! UTUnRegister + 2492 bytes
=== end AfxDumpStack() output ===
上述输出中的每行都指示最后一个函数调用的地址、包含函数调用的模块的完整路径名称以及调用的函数原型。 如果堆栈上的函数调用未在函数的确切地址发生,则会显示字节的偏移量。
例如,下表描述了上述输出的第一行:
输出 | 说明 |
---|---|
00427D55: |
最后一个函数调用的返回地址。 |
DUMP2\DEBUG\DUMP2.EXE! |
函数调用所在模块的完整路径名称。 |
void AfxDumpStack(unsigned long) |
调用的函数原型。 |
+ 181 bytes |
函数原型的地址(在本例中为 void AfxDumpStack(unsigned long) )与返回地址(在本例中为 00427D55 )的偏移量(以字节为单位)。 |
AfxDumpStack
在 MFC 库的调试和非调试版本中可用;但是,即使可执行文件在共享 DLL 中使用 MFC,该函数也始终以静态方式链接。 在共享库实现中,函数位于 MFCS42.LIB 库(及其变体)中。
若要成功使用此函数,请执行以下操作:
文件 IMAGEHLP.DLL 必须位于路径上。 如果没有此 DLL,该函数将显示错误消息。 有关 IMAGEHLP 提供的函数集的信息,请参阅图像帮助库。
堆栈上具有帧的模块必须包含调试信息。 如果它们不包含调试信息,函数仍将生成堆栈跟踪,但跟踪将不太详细。
要求
标头: afx.h
AfxEnableMemoryLeakDump
启用和禁用 AFX_DEBUG_STATE 析构函数中的内存泄漏转储。
BOOL AFXAPI AfxEnableMemoryLeakDump(BOOL bDump);
参数
bDump
[in] TRUE 指示已启用内存泄漏转储;FALSE 指示已禁用内存泄漏转储。
返回值
此标志的上一个值。
备注
当应用程序卸载 MFC 库时,MFC 库将检查内存泄漏。 此时,任何内存泄露都将通过 Visual Studio 的“调试”窗口报告给用户。
如果应用程序在加载 MFC 库之前加载另一个库,则会将该库中的一些内存分配误报为内存泄漏。 MFC 库报告错误的内存泄漏时,这些误报可能导致应用程序缓慢关闭。 在这种情况下,使用 AfxEnableMemoryLeakDump
禁用内存泄漏转储。
注意
如果使用此方法来关闭内存泄漏转储,将不会在应用程序中收到有效内存泄漏的报告。 只有确信内存泄漏报告中包含误报时才使用此方法。
要求
标头: afx.h
AfxEnableMemoryTracking
诊断内存跟踪通常在 MFC 的调试版本中启用。
BOOL AfxEnableMemoryTracking(BOOL bTrack);
参数
bTrack
将此值设置为 TRUE 可打开内存跟踪;设置为 FALSE 可将其关闭。
返回值
跟踪启用标志的上一设置。
备注
使用此函数可以禁用对已知正确分配块的代码部分的跟踪。
有关 AfxEnableMemoryTracking
的详细信息,请参阅调试 MFC 应用程序。
注意
此函数仅适用于 MFC 的调试版本。
示例
BOOL CMyWinApp::InitInstance()
{
#ifdef _DEBUG
// Disable tracking of memory for the scope of the InitInstance()
AfxEnableMemoryTracking(FALSE);
#endif // _DEBUG
// ...
#ifdef _DEBUG
// Re-enable tracking of memory
AfxEnableMemoryTracking(TRUE);
#endif // _DEBUG
return TRUE;
}
要求
标头: afx.h
AfxIsMemoryBlock
测试内存地址,以确保它表示诊断版本的 new
分配的当前活动内存块。
BOOL AfxIsMemoryBlock(
const void* p,
UINT nBytes,
LONG* plRequestNumber = NULL);
参数
p
指向要测试的内存块。
nBytes
包含内存块的长度(以字节为单位)。
plRequestNumber
指向 long
整数的指针,该整数将用内存块的分配序列号填充,如果它不表示当前活动内存块,则为零。
返回值
如果内存块当前已分配且长度正确,则为非零;否则为 0。
备注
它还根据原始分配的大小检查指定的大小。 如果函数返回非零,则 plRequestNumber 中返回分配序列号。 此数字表示相对于所有其他 new
分配对块进行分配的顺序。
示例
CAge* pcage = new CAge(21); // CAge is derived from CObject.
ASSERT(AfxIsMemoryBlock(pcage, sizeof(CAge)));
要求
标头: afx.h
AfxIsValidAddress
测试任何内存地址,以确保它完全包含在程序的内存空间中。
BOOL AfxIsValidAddress(
const void* lp,
UINT nBytes,
BOOL bReadWrite = TRUE);
参数
lp
指向要测试的内存地址。
nBytes
包含要测试的内存字节数。
bReadWrite
指定内存是用于读取和写入 (TRUE),还是仅读取 (FALSE)。
返回值
在调试生成中,如果指定的内存块完全包含在程序的内存空间中,则为非零;否则为 0。
在非调试生成中,如果 lp 不为 NULL,则为非零;否则为 0。
备注
地址不限于由 new
分配的块。
示例
// Allocate a 5 character array, which should have a valid memory address.
char* arr = new char[5];
// Create a null pointer, which should be an invalid memory address.
char* null = (char*)0x0;
ASSERT(AfxIsValidAddress(arr, 5));
ASSERT(!AfxIsValidAddress(null, 5));
要求
标头: afx.h
AfxIsValidString
使用此函数可确定指向字符串的指针是否有效。
BOOL AfxIsValidString(
LPCSTR lpsz,
int nLength = -1);
参数
lpsz
要测试的指针。
nLength
指定要测试的字符串的长度(以字节为单位)。 值为 -1 表示字符串将以 null 结尾。
返回值
在调试生成中,如果指定的指针指向指定大小的字符串,则为非零;否则为 0。
在非调试生成中,如果 lpsz 不为 NULL,则为非零;否则为 0。
示例
// Create a character string which should be valid.
char str[12] = "hello world";
// Create a null pointer, which should be an invalid string.
char* null = (char*)0x0;
ASSERT(AfxIsValidString(str, 12));
ASSERT(!AfxIsValidString(null, 5));
要求
标头: afx.h
AfxSetAllocHook
设置一个挂钩,用于在分配每个内存块之前启用对指定函数的调用。
AFX_ALLOC_HOOK AfxSetAllocHook(AFX_ALLOC_HOOK pfnAllocHook);
参数
pfnAllocHook
指定要调用的函数的名称。 有关分配函数的原型,请参阅“备注”。
返回值
如果要允许分配,则为非零;否则为 0。
注解
Microsoft 基础类库调试内存分配器可以调用用户定义的挂钩函数,以允许用户监视内存分配并控制是否允许分配。 分配挂钩函数的原型如下:
BOOL AFXAPI AllocHook(size_t,BOOL,LONG bObject
nSize
lRequestNumber
);
nSize
建议的内存分配的大小。
bObject
如果分配 CObject
派生对象,则为 TRUE;否则为 FALSE。
lRequestNumber
内存分配的序列号。
请注意,AFXAPI 调用约定意味着被调用方必须从堆栈中删除参数。
要求
标头: afx.h
AfxDoForAllClasses
为应用程序内存空间中所有可序列化的 CObject
派生类调用指定的迭代函数。
void
AFXAPI AfxDoForAllClasses(
void (* pfn)(const CRuntimeClass* pClass, void* pContext),
void* pContext);
参数
pfn
指向要为每个类调用的迭代函数。 函数参数是指向 CRuntimeClass
对象的指针,也是指向调用方提供给函数的额外数据的 void 指针。
pContext
指向调用方可以提供给迭代函数的可选数据。 此指针可以为 NULL。
注解
可序列化的 CObject
派生类是使用 DECLARE_SERIAL 宏派生的类。 每次调用传递给 pContext 中的 AfxDoForAllClasses
的指针时,该指针将传递给指定的迭代函数。
注意
此函数仅适用于 MFC 的调试版本。
示例
#ifdef _DEBUG
void DoForAllClasses(const CRuntimeClass* pClass, void* pContext)
{
ASSERT(pContext != NULL);
CString* pStr = (CString*)pContext;
*pStr += pClass->m_lpszClassName;
*pStr += _T("\n");
}
#endif
#ifdef _DEBUG
CString cStr;
AfxDoForAllClasses(DoForAllClasses, &cStr);
AfxMessageBox(cStr);
#endif
要求
标头: afx.h
AfxDoForAllObjects
为派生自已使用 new
分配的 CObject
的所有对象执行指定的迭代函数。
void AfxDoForAllObjects(
void (* pfn)(CObject* pObject, void* pContext),
void* pContext);
参数
pfn
指向要为每个对象执行的迭代函数。 函数参数是指向 CObject
的指针,也是指向调用方提供给函数的额外数据的 void 指针。
pContext
指向调用方可以提供给迭代函数的可选数据。 此指针可以为 NULL。
备注
不枚举堆栈、全局或嵌入对象。 每次调用传递给 pContext 中的 AfxDoForAllObjects
的指针时,该指针将传递给指定的迭代函数。
注意
此函数仅适用于 MFC 的调试版本。
示例
#ifdef _DEBUG
void DoForAllObjects(CObject* pObject, void* pContext)
{
int* pnCount = (int*)pContext;
pObject->AssertValid();
if (pnCount != NULL)
(*pnCount)++;
}
#endif // _DEBUG
#ifdef _DEBUG
//AfxDoForAllObjects will call the function DoForAllObjects
//For each CObject-derived object that is allocated on the heap
int nCount = 0;
AfxDoForAllObjects(DoForAllObjects, &nCount);
TRACE("%d Objects Checked\n", nCount);
#endif