The Science of Debugging
Chapter 7


7.4.2 Examining Variables

MSVC makes variable examination far too easy. Look in the variable display window and see all the variables for the current function laid out for you. For moderately complex variables, such as arrays, lists, or other pointer-dereferencing-required values, simply click on them to expand one level. Click on the new level to open up the one after that; repeat indefinately.

If you need to see global variables, you can simply type their names in, in the Watch Window. You can even perform calculations, typecasting conversions, and evaluate expressions. Simply type them into the watch window in the same manner as if you were writing the code in C.

If you have problems with the output format, you can change that too; When you type the variable name, simply append a comma and the printf-format letter. For example, c for character, d for integer, f for float, and s for string.

Feel free to play around - if a variable name or pointer reference is not valid, MSVC will simply display that fact, and nothing breaks.


As you can see above, our variable window contains our local variables, a and b, as well as their values. Our watch window contains whatever expression we type into it, even if it's a calculation or evaluation of a pointer. Both are fairly intuitive to use, so I won't worry you too much more about those. Instead, lets focus on something a bit more interesting; MSVC memory in a debug environment.

As I indicated before, some programs actually perform differently when running in debug mode; memory is allocated differently, initalization values may (or may not) be provided, and all manner of strange things happen.

These strange things are usually supposed to be transparent to the user, even if they're delving down into the assembly code, but MSVC took exception to this to provide fairly useful information to the user. What they did was to provide recoginizable byte-level fingerprints in memory, so you can examine a crash and immediately determine if you were, perhaps, freeing memory twice, or accessing an uninitalized memory area. Here's a small chart;

Potential patterns
0xFDFDFDFD No man's land (normally outside of a process)
0xDDDDDDDD Freed memory
0xCDCDCDCD Uninitialized (global)
0xCCCCCCCC Uninitialized locals (on the stack)

This chart lists the 4 types of patterns you'll see in (incorrectly used) memory. The first, no-man's land, is a reference to memory located outside of a given memory block - that is, potentially outside the function. If you see this error, you're probably overwriting an array or dereferencing some random memory value and hopping off into nowhereville. The second is straightforward as well; it's what freed memory is set to. The third and fourth are the values that ALL uninitalized variables are set to; this includes ints, floats, char pointers, really everything. You'll get these patterns if you attempt to use an uninitalized variable, which I hope should be pretty obvious.

The offical Microsoft disclaimer on these values runs something like this; "These values are undocumented and subject to change, but any sort of a signpost can be helpful while debugging. Just because you don't see those values doesn't mean that the values in memory are valid, of course. These are just some of the common patterns."

So, in short, don't depend on them, and for gods sake, don't write code to look for them. You can still use them in day-to-day debugging though, of course.



Index
7.4.1 Examining the Program 7.4.3 Examining the Stack