YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
XD++ Library
DocVizor
TFC Library
Free Products
Technical Support
UCanCode.net


Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


Visual C++ Tutorial: Visual C++ Debug / VC++ Debug / MFC Debug, ASSERT

 
 

Questions

How do I set breakpoints, set watches, and set through an executing program line-by-line? Answer

QUESTION: How do I set breakpoints, set watches, and set through an executing program line-by-line?

ANSWER: We will use the program guessage.cpp as our example. Note that we are using Visual C++ version 6. However, the steps in Visual C++ version 5 are very similar. Open Visual C++.

1. You begin by opening the file guessage.cpp as shown in the Visual C++ Build Tutorial. Visual C++ will then display the file guessage.cpp in the code window

2. Once the file guessage.cpp is open, you build an executable version of the program, as shown in the Visual C++ Build Tutorial: Select Build | Build. Visual C++ will ucancode.net if you want to create a default project workspace. Select Yes.

3. Set a breakpoint at the following line by clicking the cursor on this line, and then clicking on the "hand" (Insert/Remove Breakpoint). A red breakpoint "stopsign" appears to the left of the line of code.

    cin >> num;

4. Run guessage.cpp in debug mode by choosing Build | Start Debug | Go.

5. Note that execution stops at the point where the breakpoint was set.

6. Set a watch on the variable "num" by typing "num" in the name column of the Watch1 window in the middle of the screen.

7a. Step to the next line using Debug | Step Over (or F10).

7b. And enter your magic number and press Enter.

7c. You will see the yellow arrow (that marks the current line in the code) has move to the next, non-comment line of code and that "num" in the Watch1 window has the value you typed in for you Magic Number (here 129).

8a. Step to the next line using Debug | Step Over (or F10) and see the value of "num" change according to the calculation executed in the line of the program. Watch the yellow arrow move through the code one line at a time.

That's all.

Q: What is an assertion?
A: An assertion statement specifies a condition that you expect to hold true at some particular point in your program. If that condition does not hold true, the assertion fails, execution of your program is interrupted, and the Assertion Failed dialog box appears.

Q: What kind of asserts does Visual C++ support?
A: Visual C++ supports assertion statements based on the following constructs:

  • 'MFC assertions' for MFC program
  • 'ATLASSERT for programs that use ATL
  • 'CRT' assertions for programs that use the C run-time library
  • ANSI 'assert()' function for other C/C++ programs

Q: What good are assertions for?
A: You can use assertions to:

  • Catch logic errors
  • Check results of an operation
  • Test error conditions that should have been handled

Q: What is MFC's ASSERT?
A: A macro definition that allows you to evaluate an expression. If the expression is evaluated to 0, the macro prints a diagnostic message and aborts the program. If the condition is nonzero, it does nothing. The diagnostic message has the form

assertion failed in file _filename_ in line _linenum

where '_filename_' is the name of the source file, and '_linenum_' is the line number of the assertion that failed in the source file. In an MFC ISAPI application, an assertion in debug mode will bring up a modal dialog box; this will interrupt or hang the execution.

: Are there another MFC assertion macros?

A: Yes, you can also use one of these:

  • 'ASSERT_KINDOF(classname, pobject)' -> This macro asserts that the object pointed to is an object of the specified class, or is an object of a class derived from the specified class.
    ASSERT_KINDOF(CMyDocument, pDocument)

    if identical with
    ASSERT(pobject->IsKindOf(RUNTIME_CLASS(classname)));
  • 'ASSERT_VALID(pobject)' -> Used to test an assumptions about the validity of an object's internal state. The parameter must be an object of a class derived from 'CObject' that has an overriding version of the 'AssertValid()' member function. 'ASSERT_VALID' validates the pointer, checks against 'NULL', and calls the object's own 'AssertValid()' member functions.

Q: What about 'ATLASSERT'?
A: The 'ATLASSERT' macro performs the same functionality as the '_ASSERTE' macro found in the C run-time library.

Q: What are the CRT assertion macros?
A: The 'CRTDBG.H' header file defines the '_ASSERT' and '_ASSERTE' macros for assertion checking. The result of these macros are:

  • '_ASSERT: If the specified expression evaluates to FALSE, the file name and line number of the _ASSERT
  • '_ASSERTE': Same as _ASSERT, plus a string representation of the expression that was asserted

Q: How do I chose between '_ASSERT' and '_ASSERTE'?
A: '_ASSERTE' is more powerful because it reports the asserted expression that turned out to be 'FALSE'. This may be enough to identify the problem without referring to the source code. However, the Debug version of your application will contain a string constant for each expression asserted using '_ASSERTE'. If you use many '_ASSERTE' macros, these string expressions take up a significant amount of memory. If that proves to be a problem, use '_ASSERT' to save memory.

Q: And about the ANSI assertion funtion?

A: 'assert()' evaluates an expression and, when the result is 'false', prints a diagnostic message and aborts the program.

The ANSI 'assert' macro is typically used to identify logic errors during program development by implementing the expression argument to evaluate to 'false' only when the program is operating incorrectly. After debugging is complete, assertion checking can be turned off without modifying the source file by defining the identifier 'NDEBUG'. 'NDEBUG' can be defined with a '/D' command-line option or with a '#define' directive. If 'NDEBUG' is defined with '#define', the directive must appear before 'Assert.h' is included.

'assert' prints a diagnostic message when expression evaluates to 'false' (0) and calls abort to terminate program execution. No action is taken if expression is 'true' (nonzero). The diagnostic message includes the failed expression and the name of the source file and line number where the assertion failed.

Q: Can I see an example of 'assert()'?
A: Here is a simple example and the output. Consider the file is called 'test.cpp':

#include <assert.h>
int main()
{
int* array = NULL;
assert(array != NULL); // this should fail
return 0;
}

output is:

Assertion failed: array != NULL, file test.cpp, line 7
abnormal program termination

Q: Do asserts work in release version also?
A: No, only in debug version. In the release version of MFC, 'ASSERT' does not evaluate the expression and thus will not interrupt the program. If the expression must be evaluated regardless of environment, use the 'VERIFY' macro in place of 'ASSERT'. Because of this, never use a method that changes the state of the program as the expression or part of the expression of 'ASSERT'. In a release build, 'ASSERT' is not included in the code.

Q: What should I do when I get a "Debug Assertion Failed!" message?
A: Run your application in debugger and when you get the message press 'Retry' to debug the application. Look in the 'call stack' window (Alt+7) and go to the first (from top down) function written by you in the stack and identify the line that triggers the assertion failure.

Q: What are common causes for assertion failures?
A: Most often it is the usage of an invalid pointer or an attempt to index an array beyond its boundaries.

Q: How can 'ASSERT' help me with writing better code?
A: You build your application first as a debug version and only when it is finished you build the release version. 'ASSERT' help you identify the errors in the execution flow. You should always test pointers for validity:

void Draw(int index)
{
CFigure* pFigure
= GetFigure(index); // should return a figure from a list
// if GetFigure returns NULL the next line of code is faulty
pFigure->Draw ();
}

The correct way is:

void Draw (int index)
{
CFigure* pFigure
= GetFigure(index);
ASSERT(pFigure != NULL); // if pFigure == NULL you get an error message
if(pFigure == NULL) // this avoids the usage of a NULL pointer
return;
pFigure->Draw ();
}

In this example, I consider 'GetFigure()' a function that should always return a valid figure. The role of 'ASSERT' is to ensure that 'GetFigure()' actually does what it supposed to do and always return a valid pointer. Now if you wander what is the role of

if(pFigure == NULL) return;

the answer is to make sure that if the debug build wasn't tested enough and an error could occur in the release, the program wouldn't crash because of the use of a 'NULL' pointer.

However, if 'GetFigure()' can return a 'NULL' pointer, that pointer should not be asserted against 'NULL'.

You should also test the index used for accessing elements of arrays:

// this is a dummy example
class foo
{
int elements[10];
public
:
foo() {
/* do some initialization */ };
int
getAt(int index) const
{
ASSERT(index>
=0 && index<10);
if
(index>=0 && index<10)
return elements[index];
return
-1; // return a default value
}
}
;

 

 

 

Copyright ?1998-2007 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net