Download source files - 1.5 Kb
MFC comes with a set of several useful debugging macros. We've all used
these macros numerous times and are quite familiar with them. How many times,
however, have you been writing a piece of non-MFC code and wished you had
the same macros available? Standard C/C++ come with only one macro that is
at least similar to the MFC ASSERT macro, namely assert. However, this
particular assertion macro is not as elegant as the MFC version which
drops you directly into the code at the line of the assertion.
Or maybe you have some debugging needs that go beyond those available by
the MFC macros. Maybe you're trying desperately to track down a memory over
run bug, for instance.
Hopefully, this article will come to your rescue for these problems!
The header file found in the download, <debug.h>, defines several
macros useful for debugging code. Many of these macros will be familiar to
MFC programmers, since they go by the same name and provide the same
functionality. In fact, if MFC has been included before this header file
then the MFC versions of these macros are used. Above and beyond the MFC
macros, several other macros have been defined to provide functionality
that Microsoft forgot. Below you'll find a general description of the
macros present.
ASSERT
The ASSERT macro is identical the MFC macro of the same name. It's used
to assert conditions within code during debug builds (when _DEBUG is defined).
If the assertion fails then the program will break at the line the assertion
was made.
Example:
ASSERT(a < 1);
VERIFY
The VERIFY macro is identical to the MFC macro of the same name. It's
similar to ASSERT, but the condition is evaluated even for release builds,
although a break will occur only in debug builds.
Example:
VERIFY(pWnd = GetDlgItem(IDC_MYEDIT));
TRACE
The TRACE macro is identical to the MFC macro of the same name. It's used
to send text to the debug output window. It's syntax is similar to that of
printf.
Example:
TRACE("Name: %s\n", obj.name());
INFO
The INFO macro is similar to the TRACE macro. Unlike TRACE, INFO prefixes
the text with the file name and line number where the INFO was invoked, as
well as appending a new line.
Example:
INFO("Name: %s\n", obj.name());
DBG
The DBG macro is used to invoke code for debug builds only.
Example:
DBG(AfxMessageBox("I'm here!"));
BREAK
The BREAK macro is used to force a program to break for debug builds. When
the line where the BREAK is called is run, the program will halt and the debugger
will go to that line.
Example:
BREAK();
DECL_DOG_TAG and CHECK_DOG_TAG
These macros are two of the most complex debugging macros found in this
header. They are used to help detect memory corruption caused by memory
over runs. I acquired this technique from a magazine article some time ago.
Unfortunately, I can't recall where. If anyone knows please send me an e-mail
so I can't give proper recognition to the original author.
To use "dog tags" you first must declare them within a class definition
using DECL_DOG_TAG. After this you can verify the integrity of memory by
calling CHECK_DOG_TAG within your code. Typically you'll declare two dog
tags within a class, one as the first class member and one as the last. It's
also helpful to define a method to verify the integrety of the class by
using these dog tags. Then client code can check the validity of the class by
calling this method. See the example below for a demonstration of this.
Example:
class MyClass
{
private:
DECL_DOG_TAG(MyClassBegin);
private:
DECL_DOG_TAG(MyClassEnd);
#ifdef _DEBUG
public:
void VerifyIntegrity() const
{ CHECK_DOG_TAG(MyClassBegin); CHECK_DOG_TAG(MyClassEnd); }
#endif
};
void func(MyClass& obj)
{
DBG(obj.VerifyIntegrity());
}
Using the above code, if the object's integrity has been corrupted (typically
by a memory over run in your code) then an ASSERT will fail on a call to
VerifyIntegrity within the CHECK_DOG_TAG macro.
I hope you find this header useful. If you know of any other debugging
macros then drop me a line. I'll add them to later releases of this header.