I. debug and release versions
Sometimes the program can run in the debug version but cannot run in the release version, or vice versa. Generally, a released version means some types of optimization, while a debug version is not optimized. Let's take a look at their differences:
1. Compilation options for debugging versions
(1)/MDd,/MLd or/MTd
The Runtime Library of the debug version contains debugging symbols. The debugging heap is used to detect memory corruption and Memory leakage, and report the source code to the user. Features:
The Runtime Library of the debug version tracks the memory allocation and allows users to check for Memory leakage.
Write the 0xCD byte mode in the newly allocated memory, and use 0xCD to fill in the newly allocated memory, which helps to find data uninitialized errors.
. Write the byte mode of 0xDD in the released memory to help you find the released memory.
. Four bytes of protected data are allocated on both sides of the buffer and initialized in the byte mode of 0xFD to check the top overflow and bottom overflow of the write memory.
The source code file name and line number are recorded in each memory allocation, which helps you locate the memory allocation in the source code.
(2)/Od
This option is used to turn off the optimization switch. Because the unoptimized Code directly corresponds to the source code, it is easier to understand than the optimized code. Unoptimized code compilation and linking are faster, with a shorter debugging cycle. Due to optimization, the released version may not run better than the debug version. The optimization Code requires the compiler to make assumptions to remove redundancy, but sometimes this assumption is wrong, the removed redundancy may also cause hidden errors. For example, the release version of the frame pointer (EBP register) omits (FPO) to hide the function prototype Mismatch Error. In the synchronization exception mode (only throw statements can be thrown, the compiler defaults, under the/GX compilation option), the exception handler may be optimized, which will prevent the C ++ exception handling code in the program from securely capturing structure exceptions. In this case, you must use the asynchronous exception mode (any command will generate an exception mechanism, which is set by the/Eha compilation option ).
(3)/D "_ DEBUG"
Enable Conditional compilation and debugging code. Only when this symbol is defined can the debugging code be compiled. MFC uses the _ DEBUG symbol to determine which version of the MFC class library is linked. In the debugging version, inline is disabled by default.
(4)/ZI
Create a program database for editing and continuing. This option will enable the/GF compilation option, the/GF compilation option will remove duplicate strings, and put the strings in the read-only memory. The Edit continuation function requires special information stored in the PDB file to make the code modification effective to the debugger. If the information corresponding to the modified file is not in the PDB file, the edit continue function cannot be performed, in addition, the following message "One or more files are out of date or do not exist. ".
(5)/GZ
In the debug version, it is used to find errors found in the released version. Its functions are as follows:
. Initialize the automatic (local) variable in 0xCC mode.
When calling a function through the function pointer, check the stack pointer to check whether there are call rules that do not match.
. Check whether the stack pointer is changed at the end of the function.
(6)/Gm
Turn on the minimize relink switch to reduce the link time.
2. Compilation options for released versions
(1)/MD,/ML or/MT
Use the Runtime Library of the released version.
(2)/O1 or/O2
Turn on the optimization switch to minimize the program speed or minimize the program speed. The Optimizer may also find potential errors in the code, which may be concealed by the debug version.
(3)/D "NDEBUG"
Turn off the Conditional compilation and debugging code switch.
(4)/GF
Remove duplicate strings and place them in read-only memory to avoid improper modification.
(5)/Zi
Create a program database containing debugging symbols.
If an error occurs only in the released version, unless you are a master assembler, You Need To debug the symbols to indicate what problems have occurred to your program, the debugging symbols are stored in the database file (PDB) of the program. Visual C ++ AppWizard does not create debugging symbols for the released version by default. To create a debugging symbol, open the Project Settings dialog box, select Win32 Release, select the Common class in the C/C ++ label, and select Program Database in the debugging information, if the debugging version is selected, select Program Database for Edit and Continue (the Edit continuation option is incompatible with the optimization link and is not suitable for release ). Select the Debug class in the Link label, and then select the Debug Info and Microsoft format options. It is best not to select the Separate types option, in this way, all debugging information will be merged into a single PDB file. For a release version, select the Link tag and add "/OPT: REF" at the end of the Project options dialog box. This option prevents referenced functions and data from appearing in the executable file, this avoids unnecessary file increase. Do not use this option for debugging versions. It will disable the incremental Link (incremental linking ).
2. "Settings" menu in Visual C ++ Editor
After you open or create a Workspace that contains at least one Project, click "Settings…" in the Project menu of Visual C ++ ..." The command becomes effective. After you select it or press the hot key Alt + F7, the project Setting dialog box can be called up. The options here will affect the entire project establishment and debugging process, so it is very important.
In this dialog box, the drop-down list box in the upper-left corner is used to select a project configuration, including Win32 Debug, Win32 Release, and All comprehenations ), some options have different default values in different project configurations. The Tree View on the left shows all the files and categories of the current project. Next we will take Win32 Debug as an example to look at the functions and meanings of the four main tabs related to the project (a total of ten tabs ):
1. General Tab
This tab is relatively simple. The first option from top to bottom is used to change the method of using the MFC class library: DLL or static connection. You can switch between the two methods. The second option is used to specify the directory for storing intermediate and output files generated during the compilation and connection process. For debugging versions, the default directory is the "Debug" subdirectory under the project. The third option is used to specify whether to allow each project configuration to have its own file dependency (main finger file). Because most of the project debugging versions and release versions have the same file dependency, therefore, you do not need to change this option.
2. Debug Tab
The Debug tab contains debugging-related options. Because there are many options, they are divided into several classes. We can select different categories from the Category, tab to display the corresponding options.
In the General category, you can specify the executable file name to debug. The other three options can be used to specify the working directory for debugging, the command line parameters sent to the program at the start of debugging, and the path of the executable file during remote debugging.
3. C/C ++ Tab
The C/C ++ tab controls the Visual C ++ compiler. There are many options. The following is a Project Options edit box. The various command switches listed in the box will be transmitted to the Visual C ++ compiler as command line parameters at the start of compilation. These command switches change with other options.
In the General category, the Warning level is used to specify the Warning level for the compiler to display. If Warnings as errors is selected, each Warning displayed will cause an error, in this way, the connector cannot be started for connection after compilation. Optimizations is used to set the code optimization method. The optimization mainly aims to improve the running speed and reduce the program volume. However, sometimes these two purposes are mutually contradictory. In addition, in rare cases, the program runs normally without optimization. After the optimization measures are enabled, some inexplicable problems may occur in the program. In fact, most of these are potential errors in the program. Shutting Down optimization measures is often just a temporary solution. Debug info is used to specify the type of debugging information generated by the compiler. To use the out-of-the-box editing function of Visual C ++, you must generate the debugging information of the "Program Database for Edit and Continue" type here. Preprocessor definitions is a number of predefined macro names.
The options in the C ++ Language class involve some advanced features of the C ++ Language, including the representation of member pointers, exception handling, and runtime type information, generally, you do not need to change them. The options in the Code Generation category involve how to generate the target Code. Generally, keep the default value. In the Customize category, the six options from top to bottom have the following meanings: whether to disable Microsoft's extension to C ++, whether to allow function-level connections, and whether to eliminate repeated strings; whether to allow minimal reconstruction; whether to allow incremental compilation; whether to allow the compiler to Output its version information to the Output window at the start of running.
In the Listing Files category, you can specify the compiler to generate the browsing information and Listing file. The former can be generated by the browser information maintenance tool BSCMAKE, the latter contains the compilation commands corresponding to the C/C ++ source file after compilation. The Optimizations category allows us to control the optimization measures in more detail. After selecting Customize, we can select which Optimizations to perform, in Inline function expansion, we can specify the Extension Method for Inline functions. The Precompiled Headers class contains some options for Precompiled header files, which are generally not changed. Preprocessor categories are some options about preprocessing.
4. Link Tab
The Link tab controls the connector of Visual C ++. In the General category, you can specify the output file name and some additional library files or target files to be used during the connection. The following five options are described as follows: generate debugging information; ignore all default library files; allow incremental connection (this method can speed up the connection); generate MAP files; allow performance analysis. In Customize, select Use program database to allow Use of the program database. In the Debug category, we can specify whether the debugging information is in Microsoft format, COFF format, or both, after Separate types is selected, the connector will Separate the debugging information and put it in the PDB file. This will make the connection faster, but the debugging speed will be slower. The Input class contains some options related to the Input library file. Here we can specify to use or not use some library files or target files. In the Output class, there are some options related to the final Output executable file, which generally do not need to be changed.
3. Visual C ++ debugging tool
1. debugging window
(1) Watch)
When debugging a program, you can use the observation window to monitor variables and expressions.
(2) Quick watch)
The function is similar to the observation window.
(3) Variable Window (Variables)
The variables window has three labels: the Auto label displays the variables used by the current statement and the previous statement, the Locals label displays the local variables of the current function, and the this label displays the objects executed by the this pointer.
(4) Register window (Register)
Monitor CPU registers, flag values, and floating point stacks
(5) Memory window (Memory)
Displays the virtual memory from a specific address. The Address box allows you to specify the virtual memory Address to display.
(6) Call stack window)
Displays a series of function calls that cause execution of the Current Source Code statement. The current function is at the top of the stack.
(7) Disassembly window (Disassembly)
You can view the compilation commands generated by the compiler corresponding to the source code.
2. debugging symbols
The program database file (. pdb) contains debugging information and program information required by the Visual C ++ debugger. The debugging information includes the name and type of the variable, the function prototype, the source code line number, the layout of the class and structure, the FPO debugging information (rebuilding the stack frame), and the information required for the incremental link. For programs with the Program Database for Edit and Continue options set, PDB also contains information required to execute the Edit continuation function.
3. Use breakpoints
A BreakPoint is a mechanism that allows you to describe the environment to the debugger and set the state of the program. If there is no breakpoint, you can only trace the use of the debugger step by step in the program. In Visual C ++, you can set three types of breakpoints: Code Location breakpoint, data breakpoint, and message breakpoint.
4. Improve the debugging capability of the debugger
Use the compile time check instead of Run Time check whenever possible.
1. Use the highest compilation warning level/W4
For statements like if (x = 2), if the default warning level is/W3, no information is displayed. if it is changed to the highest warning level/W4, "waning C4706: assignment within conditional expression "warning. /W4 can give warnings that/W3 cannot give.
2. Use the/GZ compilation option in the debugging version.
The/GZ option is used to discover errors found in the released version, including uninitialized automatic (local) variables, stack errors, and incorrect function prototypes.
3. Use # pragma warning compiler instructions
You can use the # pragma warning compiler to indicate that the entire program, specific header files, specific code files, or specific warnings of a specific line of code are prohibited, depending on where you put # pragma.
4. Use a compilation rule without warning/WX
This compilation option treats all warnings as errors and can be applied only after false warnings are cleared. Sometimes the compilation warning may be reasonable. The core of the compilation warning is to discover errors, rather than suppress the warning itself. This rule is very helpful for large program development teams. The final goal is to eliminate errors rather than warnings.
5. memory space and allocation
1. Memory Allocation Error
There are two basic types of dynamic memory allocation errors: Memory Errors and memory leaks.
(1) memory error
When a pointer or the memory unit pointed to by the pointer becomes invalid, or the data structure allocated in the memory is damaged, a memory error occurs. The pointer is not initialized, the pointer is initialized to an invalid address, and the pointer is accidentally and incorrectly modified, this pointer is used after the memory area associated with the pointer is released (this pointer is called a dangling pointer), which will make the pointer invalid. When an error pointer or a VM pointer is used to write data to the memory, or the pointer is forcibly converted to an unmatched data structure, or the write data is out of bounds, the memory itself will be damaged. Deleting Uninitialized pointers, deleting non-heap pointers, deleting the same pointer multiple times, or overwriting the internal data structure of a pointer will cause a memory allocation system error.
(2) Memory leakage
Memory leakage occurs when the dynamically allocated memory is not released. Memory leakage may occur in many cases, such as not releasing the memory in all execution paths of the program, and not releasing all the memory in the destructor. The longer a program can run before it crashes, the greater the relationship between the cause of the crash and Memory leakage.
Windows will reclaim the leaked memory at the end of the program, so the memory leakage is a temporary problem. But why should we eliminate memory leaks? First, memory leakage often results in system resource leakage. Dynamic Memory Allocation usually not only represents a storage area, but also some types of system resources, such as files, windows, device context, and GDI objects. Second, high-quality programs and specific server programs must be able to run infinitely. Finally, memory leakage is often a sign of other program errors or bad programming habits.
Causes of internal reference leakage: forgot to release memory; constructor failure; Memory Leak destructor; abnormal handler for Memory leakage; multiple return statements; use the delete statement in the incorrect format.
2. memory initialization
In the debugging version, uninitialized memory in the heap is filled in the 0xCD byte mode, and the memory released in the heap is filled in the 0xDD byte mode. The initialized memory in the stack is filled in the 0xCC byte mode. In both the debug and release versions, the uninitialized global memory is initialized to 0.
3. Memory virtual address space
Windows uses a fixed set of ranges to split the 4 GB virtual address space of a process. Therefore, you can check the return value of the pointer to determine whether the pointer is valid.
(1) Windows2000 Virtual Address Space Division
0 ~ 0 XFFFF (64 KB): cannot be used to detect NULL pointer assignment (access conflict)
0x10000 (64 KB )~ 0x7FFEFFFF (2GB-64KB): private (non-retained) of Win32 processes for program code and Data
0x7FFF0000 (2GB-64KB )~ 0x7FFFFFFF (2 GB): cannot be used to prevent overwrite OS partition (access conflict)
0x800000000 (2 GB )~ 0 xFFFFFFFF (4 GB): reserved for the operating system and inaccessible (access conflict)
(2) Use of Windows2000 virtual address space
0x00030000 ~ 0x0012FFFF: thread Stack
0x00130000 ~ 0x003FFFFF: heap (sometimes the heap is located here)
0x00400000 ~ 0x005FFFFF: executable code
0x00600000 ~ 0x0FFFFFFF: heap (sometimes the heap is located here)
0x0000000 ~ 0x5FFFFFFF: App DLLs, Msvcrt. dll, Mfc42.dll
0x77000000 ~ 0 xFFFFFFFF: Advapi32.dll, Comctl32.dll, Gdi32.dll, Kernel32.dll, Ntdll. dll, Rpcrt4.dll, Shell32.dll, User32.dll
0x00400000 is the minimum base address available for all versions of Windows.
Vi. Some Debugging techniques
1. debug an endless loop
Use the Break command in the Debug menu. In Windows2000, if the program has an input request, you can use the F12 key to interrupt the program, then check the call stack of the window, or track the code in one step to find out the cause of the endless loop.
2. Use Spy ++ to debug message-Related Problems
The best way to debug messages is to use the Spy ++ tool provided by Visual C ++. Spy ++ allows programmers to view Windows, messages, processes, and threads. Spy ++ default message output: the row number is displayed in the first column. The second column shows the handle for receiving messages. "S" in the third column indicates that the message is sent by SendMessage, "P" indicates that the message is sent by PostMessage, and "R" indicates the return value of the message handle. The fourth column shows the decoded message name, Message Parameter, or return value.
3. unconventional methods
(1) re-compile your application
When your program shows abnormal or unexpected behavior, or the Visual C ++ compiler fails due to an internal compiler error, it is best to delete the Debug or Release folder in the project, re-connect from scratch.
(2) Restart Visual C ++
Visual C ++ has powerful capabilities, but some features of the compiler may also cause strange errors. If your program is very strange, you can try to clear all breakpoints, close or hide the observation window, check the Project Settings dialog box to see what has been modified recently, until Visual C ++ is restarted to eliminate abnormal behaviors caused by the Visual C ++ environment.
(3) restart Windows
When you discover abnormal or unexpected behavior in Windows or other programs, you should restart Windows to eliminate the interference caused by the operating system for debugging.