I. debugging Basics
Debugging shortcuts
F5: start debugging
Shift + F5: Stop debugging
F10: Debug to the next sentence. Here is the single-step tracking.
F11: Debug to the next sentence and follow up the internal function
Shift + F11: jump out of the current function
CTRL + F10: Debug to the cursor position
F9: Set (cancel) breakpoint
Alt + F9: Advanced breakpoint settings
Tracking debugging
1. Try to use the shortcut key for debugging.
2. Observe debugging information
3. Advanced interrupt settings
Exception debugging
Retry-> cancel-> debug
Function stack, with variables or call Stack window
Release debugging
1. Often test your debug and release versions.
2. Do not remove debuggingCode, Such as assert and trace.
3. initialize variables, especially global variables, malloc memory, and new memory.
4. When you remove a resource, make sure that you have removed all statements related to the resource (mainly in resouce. h)
5. Use Level 3 or Level 4 warning to compile your code without warning, project-> setting-> C/C ++-> WarningLevel (the Chinese version is project-> property-> C/C ++-> General-> warning level)
6. Change _ debug to ndebug for debugging, project-> setting-> C/C ++-> preprocessordefinitions (the Chinese version is project-> properties-> C/C ++-> pre-processor-> pre-define) (this is one of the important differences between debug and release compilation)
7. debug in releaseSource code, Project-> setting-> C/C ++-> debug info select programdatabase (the Chinese version is project-> properties-> C/C ++-> General-> debugging information format-> used to "edit and continue"ProgramDatabase), project-> setting-> link select Generate debug info (Chinese version is project-> properties-> linker-> debugging-> Generate debugging information)
8. Read code with special attention to stacks and pointers
II,TraceMacro
When the debug target is selected and the afxtraceenabled variable is set to true, the trace macro is activated. However, in the release version of the program, they are completely forbidden. The following is a typical trace statement:
...
Int ncount = 9;
Cstring strdesc ("Total ");
Trace ("Count = % d, description = % s \ n", ncount, strdesc );
...
We can see that the trace statement works a bit like the printf statement in C language. The number of Trace macro parameters is variable, so it is very easy to use. If you view the source code of MFC, you cannot find the trace macro, but you can only see trace0, trace1, trace2, and trace3 macros. Their parameters are 0, 1, 2, and 3, respectively.
My personal conclusion: Recently I saw network programming encounter trace statements, but I don't know where to output them. I did not find any materials for one night. I finally found them today. The method is as follows:
1. Add a trace statement to MFC
2. In tools> mfctracer, select enable tracing and click OK.
3. debug and run go (F5) (Note: not execute '! 'The reason why we couldn't see trace content in the past is that it wasn't debugging, '! ', Remember, remember)
4. The trace content will be displayed in the debug window in the output. The debug execution will automatically jump from the build window to the debug window, where the trace content will be displayed, ^_^
The following is a detailed description of the trace:
====================================
Trace macro is very useful for program debugging in VC and has functions similar to printf. This macro only appears in the debug version of the program, when release is enabled, the macro disappears completely, helping you reduce the amount of code when debugging is also performed.
The format is as follows:
Trace ("ddddddddddd ");
Trace ("Wewe % d", 333 );
There are also trace0, trace1, trace2... Corresponding to 0, 1, 2, respectively .. Parameters
Trace information is output to the output window of the vc ide environment (which window Indicates the project error prompt you compile), but it is limited to running your debug version program in the VC.
Trace information can also be captured using debugview. In this case, you cannot run your program in the vc ide environment, but run the build debug version program separately, in this case, you can see the output in debugvie format in the debugview window.
There are four trace usage methods in VC:
Trace1 is the output string without dynamic parameters, similar to C's printf ("output string ");
Trace2: the string in can contain a parameter output, similar to C's printf ("... % d", variable );
Trace3: can contain two parameter outputs, similar to C's printf ("... % d... % F", variable 1, variable 2 );
Trace4 can be output with three parameters, similar to C's printf ("... % d, % d, % d", variable 1, variable 2, variable 3 );
The trace macro is like the printf function we used in the C language before, so that the program outputs some debugging information during the running process, so that we can understand some of the program status. But the difference is:
The trace macro outputs only in the debugging status, and the printf function used previously has outputs in all circumstances. Like the printf function, the trace function can accept multiple parameters, for example:
Int x = 1;
Int y = 16;
Float z = 32.0;
Trace ("this is a trace statement \ n ");
Trace ("the value of X is % d \ n", X );
Trace ("x = % d and Y = % d \ n", x, y );
Trace ("x = % d and Y = % X and Z = % F \ n", x, y, z );
Note that the trace macro only works for the debug project. In the release project, the trace macro is ignored.
III,AssertMacro
If you have designed a function, the function requires a pointer pointing to the document object as a parameter, but you mistakenly call this function with a view pointer. This fake address will cause damage to the visual data. Now, this type of problem can be completely avoided, as long as an Assert test is implemented at the beginning of the function, to detect whether the pointer actually points to a document object. Generally, programmers should routinely use assertion at the beginning of each function. The assert Macro will judge the expression. If an expression is true, the execution will continue. Otherwise, the program will display a message and pause, you can choose to ignore this error and continue or terminate the program or jump to the debug tool. The following example demonstrates how to use an Assert macro to verify a statement.
Void Foo (char P, int size)
{
Assert (P! = 0); // check whether the pointer to the buffer is valid.
Assert (size> = 100); // check that the buffer contains at least 100 bytes
// Do the foo Calculation
}
These statements do not generate any code unless the-Debug processor flag is set. Visual c ++ only sets these labels in the debug version, but not in the release version. When-Debug is defined, two assertions generate the following code:
// Assert (P! = 0 );
Do {
If (! (P! = 0) & afxassertfailedline (-file-,-line -))
Afxdebugbreak ();
} While (0 );
// Assert (size ≥ 100 );
Do {
If (! (Size >= 100) & afxassertfailedline (-file-,-line -))
Afxdebugbreak ();
} While (0 );
The do-while loop encapsulates the entire assertion in a separate program block, which makes the compiler compilation very comfortable. The IF statement calculates the expression value and calls the afxassertfailedline () function when the result is zero. This function will pop up a dialog box with three options "cancel, retry or ignore". When you select "retry", it returns true. A retry will call the afxdebugbreak () function to activate the debugger.
Afxassertfailedline () is an unofficially announced function. Its function is to display a message box. The source code of this function resides in afxasert. cpp. The-file-and-line-statements in the function are processor flags that specify the source file name and the current row number respectively.
Afxassertfailedline () is an unofficially announced function. Its function is to display a message box. The source code of this function resides in afxasert. cpp. The-file-and-line-statements in the function are processor flags that specify the source file name and the current row number respectively.
IV,VerifyMacro
Because assertion can only play a role in the debug version of the program, the expression cannot contain value assignment statements, add statements (++), or reduce statements (--), because, these statements actually change data. Sometimes you may want to verify a dynamic expression and use a value assignment statement. Then we can use the verify macro to replace assert. For example:
Voidfoo (char P, int size)
{
Char Q;
Verify (q = P );
Assert (size> = 100 );
// Do the foo Calculation
// Do the foo Calculation
}
In debug mode, assert and verify are the same, but in release mode, the verify macro still tests the expression, but assertion does not play any role. In release mode, the assert statement is deleted.
Note that if you mistakenly use a dynamic expression in an Assert statement, the compiler ignores it without warning. In release mode, the expression will be deleted without sound, which will cause program operation errors. Because release programs usually do not contain debugging information, such errors are hard to be found.
V. VC advanced debugging method-condition and data breakpoint settings
(1) Position breakpoint (Locationbreakpoint)
The most common breakpoint is a normal position breakpoint. A position breakpoint is set in a line of the source program by pressing F9. However, for many problems, this simple breakpoint has limited function. For example, the following code:
Void cfordebugdlg: onok ()
{
For (INT I = 0; I <1000; I ++) //
{
Intk = I * 10-2; // B
Sendto (k); // C
Inttmp = dosome (I); // d
Trace0 ("the content to be output here"); // some useful information can be output here, and you can also output the I value.
Intj = I/tmp; // E
}
}
// In fact, we can also use other methods to adjust the same. You can use the trace0 macro to output every result in the loop. We can also see the output result in debug, when a problem occurs, the output results may be different. We can analyze the results in debug to find out the problem.
When this function is executed, the program crashes in line E and finds that TMP is 0 at this time. Assuming that TMP should not be 0, why is it 0 at this time? So it is best to track how the dosome function runs in this loop, but because it is in the loop body, if you set a breakpoint in line E, you may need to press F5 (GO) many times. In this way, it is very painful to keep pressing. You can easily solve this problem by using the vc6 breakpoint Modification Conditions. The procedure is as follows.
1 Ctrl + B Open the breakpoint setting box, such:
Figure 1 Set advanced position breakpoint
2. Select the breakpoint where Row D is located, and then click the condition button. In the bottom edit box of the pop-up dialog box, enter a large number, depending on the application. Here 1000 is enough.
3. Press F5 to run the program again, and the program is interrupted. CTRL + B Open the breakpoint box and find the breakpoint followed by a series of instructions:... 487 times remaining. It means that the remaining 487 times are not executed, that is to say, an error occurs when the execution reaches 513 (1000-487. Therefore, as described in step 2, change the number of skips for this breakpoint to 1000.
4. Run the program again. The program executes 513 cycles and stops at the breakpoint automatically. In this case, we can carefully check how dosome returns 0. In this way, you can avoid finger pain and save time.
Let's look at other Modification Conditions of the location breakpoint. For example Figure 1 As shown in, under "Enter the expression to be evaluated:", you can enter some conditions. When these conditions are met, the breakpoint starts. For example, if we need to stop the program when I is 100, we can enter "I =" in the editing box. 100" .
In addition, if you enter only the variable name in the edit box, the breakpoint starts only when the variable changes. This is convenient for detecting when a variable is modified, especially for some large programs.
Using the Modification Conditions of the location breakpoint can greatly solve some problems.
( 2) Data breakpoint ( Databreakpoint )
During software debugging, some data may be inexplicably modified (for example, some arrays may overwrite other variables ), finding out where the code causes this memory to be changed is tricky (without the help of the debugger ). The proper use of data breakpoints can help you quickly locate when and where the data is modified. For example, the following program:
# Include "stdafx. H"
# Include <string. h>
Int main (INT argc, char * argv [])
{
Charszname1 [10];
Charszname2 [4];
Strcpy (szname1, "Shenzhen ");
Printf ("% s \ n", szname1); //
Strcpy (szname2, "vckbase"); // B
Printf ("% s \ n", szname1 );
Printf ("% s \ n", szname2 );
Return0;
}
The output of this program is
Szname1: Shenzhen
Szname1: ase
Szname2: vckbase
First, let me analyze why this is the result! First, you set a breakpoint in strcpy (szname1, "Shenzhen"); F9, and then run the program F5. This is the breakpoint set by the program, as shown in figure
See, the cause of the problem is here. The address allocated by the system to szname2 is 0x0012ff70, which is 4 bytes. Then, it is four bytes after 0x0012ff70, start allocating the 10 bytes of szname1, that is, allocating 10 bytes at 0x0012ff74,
F10 one-step tracking, to printf ("% s \ n", szname1) this line, as shown in
The space allocated by szname1 has been attached with a value.
F10 goes to the next printf ("% s \ n", szname1,
Because the space allocated by szname1 and szname2 is continuous, when szname2 is assigned a value greater than the byte, the content of szname1 is overwritten, so when we output the results, we can see unexpected results,
So how to debug it? The following describes the specific method.
When Will szname1 be modified? Because szname1 code is not significantly modified. We can first set a normal breakpoint in line A, F5 runs the program, and the program stops in line. Then we set another data breakpoint. For example:
Figure 2 data breakpoint
F5 continues to run. The program stops at line B, indicating that szname1 has been modified in code B. Why didn't I modify szname1 at location B? However, the debugger specifies this line. Generally, this line won't be wrong, so let's just take a look at the program. Oh, you found that szname2 has only 4 bytes, and strcpy has 7 bytes, therefore, szname1 is overwritten.
data breakpoint is not only valid for variable changes, but can also be used to set whether the variable is equal to a certain value. For example, you can change the Red Circle in Figure 2 to the condition "szname2 [0] = '''y' '''", when the first character of szname2 is Y, the breakpoint starts.
it can be seen that a big difference between the data breakpoint and the position breakpoint is that you do not need to specify which line of code to set the breakpoint.
(3) Others
1. Set a breakpoint in the call Stack window, select a function, and press F9 to set a breakpoint. In this way, the required functions can be quickly returned from in-depth function calls.
2 set next statement command (in the debug process, right-click the command in the menu)
This command points the EIP of the program to different code lines. For example, if you are debugging the above Code and running it in line A, but you do not want to run line B and line C code, you can right-click Row D, then "set next statement ". The debugger does not execute lines B and C. As long as it is in the same function, this command can be executed before or after the jump. Flexible use of this function can greatly save debugging time.
3 Watch window
The Watch window supports a wide range of data formatting functions. If you enter 0x65, U, 101 is displayed in the right column.
Real-time display of Windows API call errors: Enter @ err, HR in the left column.
Call the function in the watch window. Remind you to clear the function immediately after calling it in the watch window. Otherwise, the debugger calls this function at each step during one-step debugging.
4. The messages breakpoint is not very practical. It can basically be replaced by the breakpoint described above.
Sat. VC debugging environment settings
To debug a program, you must first include debugging information in the program. Generally, the debug configuration in a project created from Appwizard automatically contains debugging information, the program designer can add debugging information in any configuration, including the release version.
To add debugging information, follow these steps:
Open the projectsettings dialog box (you can press the shortcut key Alt + F7 to open it, or open it through the IDE menu Project/settings)
Select the C/C ++ page, and select general in category. A debug info drop-down list box is displayed. The debugging information options include:
Command Line Project Settings description
No none no debugging information
The/ZD line numbers only target file or executable file only contains the global and exported symbols and code line information, and does not contain the symbol debugging information.
/Z 7 C 7.0-the compatible target file or executable file contains the row number and all symbol debugging information, including the variable name and type, function and prototype.
/Zi program database creates a library (PDB), including the type information and symbol debugging information.
/Zi program databasefor
In addition to the previous/Zi functions, edit and continue allows you to modify and continue the code during debugging. This option also invalidates the optimization function set by # pragma.
Select the link page and select the check box "generate debuginfo". This option will allow the connector to write debugging information into the executable file and DLL
If the options above program database are set on the C/C ++ page, link incrementally can be selected. By selecting this option, the program can be compiled (that is, incremental compilation) on the basis of the previous compilation, rather than starting from the beginning each time.
Collect metadata and deny and collect data.