About debug & release
In the process of using VC to develop software, just when you want to enjoy the excitement, you suddenly find that the release and debug running results are inconsistent or even wrong, and release is not convenient for debugging, it is really a good deal, but it hurts, and the problem always needs to be solved. The following describes some of my experiences to see if it is one of them:
1. variables.
As we all know, the operations performed by debug and release when initializing variables are different. debug assigns each byte
0xcc (note 1), while the value of release is almost random (I want to allocate it directly from the memory and it has not been initialized ). This makes it clear that if yourProgramIf a variable is not initialized
If it is referenced, it is very likely that an exception occurs: being used as a control variable will lead to inconsistent process guidance; being used as an array subscript will cause the program to crash; it is more likely that other variables are inaccurate and other errors are caused. Therefore
It is the easiest and most effective way to initialize a default value for a variable immediately after it is declared. Otherwise, if the project is too large, you can find no place to find it.CodeErrors may be ignored and not noticed in debug mode, such
In the debug mode, most arrays do not go out of bounds and are exposed in the release. This is difficult to find out: (you should pay more attention to it .)
2. Customize message parameters.
MFC provides us with a good message mechanism and adds custom messages, so I don't need to talk about the benefits. There are also debug and
Release problems? The answer is yes. When declaring the function body of a custom message, you will often see the following statement: afx_msg lresult
Onmessageown ();
Debug usually does not have any problems, but when you use message transmission in release and multithreading or between processes, it will lead to errors such as invalid handles. The direct cause of this error is elimination.
If the parameter of the message body is not added, it should be written as afx_msg lresult onmessageown (wparam, lparam
Lparam); (note 2)
3. There is no error in release mode, but an error is reported in debug mode.
In this case, most of them are caused by Incorrect code writing. You can check the source code of MFC and find
A lot of assert statements (assertions). This macro is only valid in debug mode, so it is clear that the release version does not report errors, but ignores errors rather than no errors, which may exist
This is a big risk. It is easier to debug in debug mode. Check your code carefully.
4. assert, verify, trace ...... debug macro
This situation can be easily explained. For example, enter assert in VC.
Then, select the place where the macro is defined by F12. Here, you can find that the assert in debug needs to execute afxassertfailedline, and the macro under release
Is "# define assert (f)
(Void) 0 )". Therefore, do not use program variables such as I ++ write statements to debug macro statements. Verify is an exception, "# define
Verify (f) (void) (f) ", that is, execution, the role here will not be pursued, interested in your own research :).
Summary:
Different debugging and release problems often occur at the beginning of code writing. 99% is caused by Incorrect code writing, so do not change
If you don't move it, it's the root cause of system problems or compiler problems. I used to encounter this situation. I started to pay attention to it after I had learned it again and again. Now I have written good code.
I haven't encountered this problem for a long time. The following are several aspects to avoid. Even if there is no such problem, you should pay attention to it:
1. Pay attention to the initialization of variables, especially pointer variables, array variables (in large cases, another consideration ).
2. Standard Writing of custom messages and other declarations
3. It is best to comment out the code after debugging a macro.
4. Try to use try-catch (...)
5. Try to use the module to make it clear and easy to debug.
Note 1:
AFC users provide:
The debug version is initialized to 0xcc because 0xcc is an int 3 single-step interrupt command in x86, so that the program will stop when it encounters 0xcc, this is the same as that of the JMP 0000 statement when programming a single-chip computer.
NOTE 2:
I wonder if you have ever encountered this situation. I am not sure the specific reason. Is it because the wparam + lparam space is allocated according to the default parameters and the application memory space is damaged? You can also add them as experts.
As a result, it seems that the parameter is in the stack when the function is called. Because the message of MFC is written in macros, if the onmessage () function is defined, the compilation can pass, but after one call, the stack pointer is offset. And then...
Debug & Release 2
The debug version includes debugging information, so it is much larger than the release version (which may be several hundred kb to several Mb ). As to whether DLL support is required, we mainly look at the compilation options you use. If it is based on
For ATL, the requirements for DLL in debug and release versions are similar. If you use the dynamic library of MFC as the compilation option, you need to support libraries such as mfc42d. dll.
The release version must be supported by mfc42.dll. Wrong release buildSource codeDebugging, regardless of the MFC diagnostic macro, using the MFC
Release library, compile ten to optimize the application speed, while debug
Build, on the contrary, allows debugging of source code. You can define and use the diagnostic macro of MFC and use the debug library of MFC, without optimizing the speed.
I. essential differences between debug and release compilation methods
Debug is usually called a debug version. It contains debugging information without any optimization, so that programmers can debug programs easily. Release is called a release version. It is often optimized to optimize the code size and running speed, so that users can use it well.
The real secret of debug and release lies in a set of compilation options. The options for the two are listed below (of course, there are other options, such as/FD/Fo, but the difference is not important. Usually they will not cause the release version error and will not be discussed here)
Debug version:
/MDD/MLD or/MTD use the debug Runtime Library (the runtime function library of the debug version)
/OD turn off the optimization Switch
/D "_ debug" is equivalent to # DEFINE _ Debug. Enable the compile and debug code switch (mainly
Assert function)
/Zi creates the edit and continue (Edit to continue) database, so that the database has been debugged
If the source code is modified, you do not need to re-compile it.
/GZ helps capture Memory Errors
/When GM is enabled, can I minimize the heavy chain and send it to your lips?
Release Version:
/MD/ml or/MT use the runtime function library of the released version
/O1 or/O2 optimization switch to minimize or minimize the program
/D "ndebug" Disable the Conditional compilation and debugging code switch (that is, do not compile the assert function)
/GF combines repeated strings and puts string constants in read-only memory to prevent
Modified
In fact, there is no essential limit between debug and release. They are just a set of compilation options, and the compiler only acts according to the predefined options. In fact, we can even modify these options to get optimized debugging versions or release versions with trace statements.
Ii. under which circumstances will the release version go wrong?
With the above introduction, let's compare these options one by one to see how release errors are generated.
1.
Runtime Library: Specifies the runtime function library to be linked, which usually only affects the program performance. Runtime of the debug version
The library contains debugging information and uses some protection mechanisms to help identify errors. Therefore, the performance is inferior to the release version. Runtime provided by the compiler
The library is usually stable and does not cause release errors. It is caused by the debug Runtime
Library enhances error detection, such as heap memory allocation. Sometimes debug errors occur but release
Normal phenomenon. It should be pointed out that, if the debug is wrong, even if the release is normal, the program must have a bug.
But it may be that a certain run of the release version has not been shown.
2. Optimization: This is the main cause of errors, because the source program is basically translated directly when optimization is disabled, and the compiler will make a series of assumptions after optimization is enabled. There are several types of errors:
(1)
Frame pointer omitted (FPO for short)
): During function calling, all call information (return address, parameters) and automatic variables are stored in the stack. If the declaration and implementation of a function are different (parameters, return values, and call methods), an error occurs.
---- However, in debug mode, stack access is implemented through EBP
The address implementation stored in the register. If no errors such as array out-of-bounds (or not many) occur, the function can normally be executed. In the release mode, optimization will be omitted.
The base address pointer of the EBP stack. When a global pointer is used to access the stack, the returned address error is caused by a program crash. C ++
Can check the majority of such errors, but if forced type conversion is used, it will not work. You can force/Oy-in the release version-
Compile the option to turn off frame pointer omitting to determine whether such errors occur. Common Errors include:
● An error occurred while writing the message response function of MFC. Correct should be
Afx_msg lresult onmessageown (wparam, lparam );
On_message
Macro contains forced type conversion. One way to prevent this error is to redefine the on_message macro and add the following code to stdafx. h.
(After # include "afxwin. H ")
# UNDEF on_message
# Define on_message (message, memberfxn )\
{Message, 0, 0, 0, afxsig_lwl ,\
(Afx_pmsg) (afx_pmsgw) (static_cast <lresult (afx_msg_call \
Cwnd: *) (wparam, lparam)> (& memberfxn )},
(2)
Volatile variable: Volatile
Tells the compiler that the variable may be modified by unknown methods (such as systems, other processes, and threads) outside the program ). To improve program performance, the optimizer usually places some variables in registers (similar
Register
Keyword), while other processes can only modify the memory where the variable is located, and the value in the Register remains unchanged. If your program is multi-threaded, or you find that the value of a variable does not match the expected value, you are sure that it is correct.
If the settings are correct, you may encounter such problems. This type of error is sometimes manifested as the program has the fastest optimization error and the smallest optimization is normal. Add volatile to variables that you think are suspicious.
Try.
(3) Variable Optimization: The optimization program optimizes the variables based on the usage of the variables. For example, a function has an unused variable in
In debug, it may mask an array out of bounds, while in release
In version, this variable is likely to be optimized. In this case, the array out of bounds will destroy useful data in the stack. Of course, the actual situation is much more complicated than this. Related errors include:
● Unauthorized access, including array out-of-bounds and pointer errors. For example
Void FN (void)
{
Int I;
I = 1;
Int A [4];
{
Int J;
J = 1;
}
A [-1] = 1; // Of course the error is not so obvious. For example, the subscript is a variable.
A [4] = 1;
}
J has an out-of-range scope when the array is out of bounds, but its space is not reclaimed, So I and j will cover up the out-of-bounds. The release version may be optimized because I and j are not very useful, so that the stack is damaged.
3. _ debug and ndebug: When _ debug is defined, the assert () function is compiled, but ndebug is not compiled. In addition, there are a series of assertion Macros in VC ++. This includes:
Ansi c asserted void assert (INT expression );
C Runtime lib assert (booleanexpression );
_ Asserte (booleanexpression );
MFC assert (booleanexpression );
Verify (booleanexpression );
Assert_valid (pobject );
Assert_kindof (classname, pobject );
ATL assertion atlassert (booleanexpression );
In addition, the compilation of the trace () macro is also controlled by _ debug.
Institute
All these assertions are compiled only in the debug version, but are ignored in the release version. The only exception is verify ()
. In fact, all these macros call assert ()
Function, but some library-related debugging code is appended. If you add any program code to these macros, not just a Boolean expression (for example, a value assignment, a function call that can change the value of a variable)
), So release
Version will not perform these operations, resulting in errors. It is easy for beginners to make such mistakes, and the search method is also very simple, because these macros are listed above, as long as you use the VC ++
The find in files function finds the place where these macros are used in all files of the project and then checks them one by one. In addition, some experts may also join
# Pay Attention to Conditional compilation such as ifdef _ debug.
By the way, it is worth mentioning that verify ()
Macro. This macro allows you to put program code in a Boolean expression. This macro is usually used to check windows APIs.
. Some may abuse verify () for this reason, which is actually dangerous because verify ()
It violates the idea of assertions and cannot completely separate the program code from the debugging code, which may cause a lot of trouble in the end. Therefore, experts suggest using this macro as little as possible.
4./GZ option: This option will do the following:
(1)
Initialize memory and variables. Including initializing all automatic variables with 0xcc, 0xcd (cleared data)
Initialize memory allocated in the heap (that is, dynamically allocated memory, such as new), 0xdd (dead data)
Fill in the released heap memory (such as delete), 0xfd (defencde data)
Initialize the protected memory (debug
Protection memory is added before and after the dynamic memory allocation to prevent out-of-bounds access). The words in the brackets are the mnemonic words recommended by Microsoft. The advantage of doing so is that these values are large and it is impossible to act as pointers (and
32
In a bit system, pointers are rarely odd values. In some systems, odd pointers may produce runtime errors.) These values are rarely encountered as values, and they are easy to recognize, therefore, it is beneficial
Errors encountered only when the release version is found in the debug version. Note that many people think that the compiler will use 0
To initialize the variable. This is incorrect (and it is not conducive to finding errors ).
(2) When a function is called through the function pointer, the matching of the function call is verified by checking the stack pointer. (Prevent original form mismatch)
(3) Check the stack pointer before the function returns, and confirm that it has not been modified. (Avoid out-of-bounds access and original form mismatch. When combined with the second item, you can roughly simulate frame pointer omitting FPO)
The/GZ option usually causes errors in the debug version and the release version is normal, because uninitialized variables in the release version are random, this may cause the pointer to point to a valid address and mask illegal access.
In addition, options such as/GM/GF have fewer errors, and their effects are obvious and easy to find.
Debug & Release 3
Debug is usually called a debug version. It contains debugging information without any optimization, so that programmers can debug programs easily. Release is called a release version. It is often optimized to optimize the code size and running speed, so that users can use it well.
The real secret of debug and release lies in a set of compilation options. The options for the two are listed below (of course, there are other options, such as/FD/Fo, but the difference is not important. Usually they will not cause the release version error and will not be discussed here)
| Debug version |
| Parameters |
Description |
| /MDD/MLD or/MTD |
Use the debug Runtime Library (the runtime function library of the debug version) |
| /OD |
Turn off the optimization Switch |
| /D "_ debug" |
Equivalent to # DEFINE _ Debug. Enable the compilation and debugging code switch (mainly for the assert function) |
| /Zi |
Create the edit and continue database, so that you do not need to re-compile the source code if the source code is modified during debugging. |
| /GZ |
Helps capture Memory Errors |
| /GM |
Turn on the minimize reconnection switch to reduce the link time |
| Release Version |
| Parameters |
Description |
| /MD/ml or/mt |
Use the runtime function library of the released version |
| /O1 or/O2 |
Optimize the switch to minimize or minimize the program |
| /D "ndebug" |
Turn off the Conditional compilation and debugging code switch (that is, do not compile the assert function) |
| /GF |
Merges duplicate strings and puts string constants in read-only memory to prevent modification. |
In fact, there is no essential limit between debug and release. They are just a set of compilation options, and the compiler only acts according to the predefined options. In fact, we can even modify these options to get optimized debugging versions or release versions with trace statements.
How to "debug" release programs
When debugging succeeds but the release fails, it is obviously very frustrating and often cannot be started. If you have read the above analysis and combined the specific performance of the error, it is good to quickly find the error. However, if you cannot find it at the moment, the following provides some strategies in this case.
| 1. |
As mentioned above, debug and release are only the differences between a set of compilation options. In fact, there is no definition to distinguish them. We can modify the release To narrow down the error range. As mentioned above, you can change the release options to the corresponding debug options one by one, for example,/MD to/MDD and/O1. Change to/OD or run time to program size optimization. Note: You can change only one option at a time to see which option the error disappears, and then find the option-related error accordingly. These options are Project \ Settings... can be selected directly through the list, usually not manually modified. Since the above analysis is quite comprehensive, this method is the most effective. |
| 2. |
In the programming process, you should always pay attention to testing the release version, so as to avoid too much code at the end, and the time is very tight. |
| 3. |
Use the/W4 warning level in the debug version to obtain the maximum error information from the compiler. For example, if (I = 0) will cause/W4 Warning. Do not ignore these warnings. This is usually caused by bugs in your program. But sometimes/W4 will bring a lot of redundant information, such as unused function parameters Warning, while many message processing functions ignore some parameters. We can use:# Progma warning (Disable: 4702) /// Disable //... # progma warning (default: 4702) // re-Allow to temporarily disable a warning or use # progma Warning (push, 3) // set the warning level to/W3 //... # progma warning (POP) // reset /W4 to temporarily change the warning level. Sometimes you can only use/W4 in the code that is considered suspicious. |
| 4. |
You can also debug your release version like debug, as long as you add debugging symbols. In Project/settings..., select Settings for "Win32 release", select the C/C ++ label, and select general and debug info for category. Select Program database. Add "/OPT: ref" at the end of the link tag project options" (Do not enter quotation marks ). In this way, the debugger can use PDB. File. However, during debugging, you will find it difficult to set breakpoints and to find variables-these are all optimized. Fortunately, call stack The window still works normally. Even if the frame pointer is optimized, the stack information (especially the return address) can still be found. This is helpful for locating errors. |
VC-Project setting-debug-project option syntax
-Optimization-
/O1 minimize space
/OP [-] Improve floating point consistency improve floating-Pt consistency
/O2 maximum speed maximize speed
/OS preferred code space favor code space
/OA assume there is no alias assume no aliasing
/OT preferred code speed favor code speed
/Ob Inline expansion (default n = 0) Inline expansion (default n = 0)
/Ow assume that the cross-function alias assume cross-function aliasing
/OD disable optimization (default) Disable optimizations (default)
/Ox maximization option. (/Ogityb2/GS) Maximum opts. (/ogityb1/GS)
/Og enable global optimization
/Oy [-] Enable framework pointer to omit enable frame pointer Omission
/OI enable the built-in function enable intrinsic functions
-Code Generation-
/G3 is 80386 optimized optimize for 80386
Optimize optimize for 80486 for 80486
/GR [-] Enable C ++ rtti enable C ++ rtti
/G5 optimize for Pentium
/G6 optimized optimize for Pentium Pro
/GX [-] Enable C ++ Exception Handling (same as/ESCS) Enable C ++ EH (same as/ESCS)
/EHS enable synchronous C ++ Exception Handling enable synchronous C ++ eh
/GD optimizes optimize for Windows DLL
/GB for mixed model optimization (default) Optimize for blended model (default)
/EHA enable asynchronous C ++ Exception Handling enable asynchronous C ++ eh
/Gd _ cdecl call Convention _ cdecl calling convention
/EHC extern "C" Default Value: nothrow extern "C" defaults to nothrow
/GR _ fastcall call Convention _ fastcall calling convention
/GI [-] Enable incremental compilation enable incremental compilation
/GZ _ stdcall call Convention _ stdcall calling convention
/GM [-] Enable minimum rebuild enable minimal rebuild
/Ga optimizes optimize for Windows Applications
/GF enable string pool enable string pooling
/Qifdiv [-] Enable Pentium fdiv to fix enable Pentium fdiv fix
/GF enable the read-only string pool Enable Read-Only string pooling
/Qi0f [-] Enable Pentium 0x0f to fix enable Pentium 0x0f fix
/Gy separates the linker function separate functions for linker
/GZ enable runtime debugging check enable runtime debug checks
/GH enable hook function call
/Ge force stack check for all functions force stack checking for all funcs
/GS [num] disable stack check call disable stack checking CILS
-Output file-
/FA named assembly list file name Assembly listing file
/FO name object file
/Fa [SC] configure the Assembly List configure Assembly listing
/FP naming precompiled header file name precompiled header file
/FD name. PDB file name. PDB File
/FR name source browser file name source browser File
/Fe name the executable file name Executable File
/FR name extension. SBR file name extended. SBR File
/FM name ing file name Map File
-Pre-processor-
/FI naming forces include file name forced include file
/C does not extract the comment don't strip comments
/U remove the predefined macro remove predefined macro
/D {=|#} definition macro define macro
/U remove all predefined macros
/E directs preprocessing to standard output preprocess to stdout
/I add to the search path containing files add to include search path
/EP directs preprocessing to the standard output. do not include the row number preprocess to stdout, no # Line
/X ignore "standard location" Ignore "standard places"
/P preprocessing to file preprocess to file
-Language-
/Zi enable debugging information
/ZL ignores the default library name omit default library name in. obj.
/Zi enable the "edit and continue" function of debugging information Enable Edit and continue debug info
/ZG generates the function prototype generate function prototypes
/Z7 enable the old debug information enable old-style debug info
/Zs only performs syntax check only
/ZD only requires line number debugging information line number debugging info only
/VD {0 | 1} disable/enable vtordisp
/ZP [N] wraps the structure pack structs on n-byte boundary on the N-byte boundary.
/Vm pointing to the member's pointer type of pointers to members
/Za disable extension (/OP) Disable extensions (implies/OP)
/Nobool disable the "bool" keyword disable "bool" keyword
/Ze enable extension (default) enable extensions (default)
-Miscellaneous-
/?, /Help print this help message
/C is compiled only and does not link compile only, no link
/W sets the warning level (default n = 1) set warning level (default n = 1)
/H maximize external Name Length Max external Name Length
/J the default char type is unsigned
/Nologo cancel display copyright message suppress copyright message
/Wx treats the warning as an error treat warnings as errors
/TC compile the file as. c compile file as. c
/YC create. PCH file create. PCH File
/TP compile the file as. cpp compile file as. cpp
/Yd put the debugging information in each. OBJ put debug info in every. OBJ
/TC compile all files into. c compile all files as. c
/TP compile all files into. cpp compile all files as. cpp
/Yu use the. PCH file use. PCH File
/V: Set version string
/Yx automatic. PCH file automatic. PCH
/W disable all warnings
/ZM maximum memory allocation (% by default) Max memory alloc (% of default)
-Link-
/MD and msvcrt. Lib link with msvcrt. Lib
/MDD and msvcrtd. Lib debugging Library link with msvcrtd. Lib debug lib
/Ml and libc. Lib link with libc. Lib
/MLD and libcd. Lib debugging Library link with libcd. Lib debug lib
/MT and libcmt. Lib link with libcmt. Lib
/MTD and libcmtd. Lib debugging Library link with libcmtd. Lib debug lib
/LD create. dll create. dll
/F set the stack size set stack size
/LDD create. dll debugging library create. dll debug libary
/Link [Linker Options and libraries] [Linker Options and libraries]