I. Essential difference between Debug and Release compilation
Debug is often referred to as a debug version, which contains debugging information and does not make any optimization, which is convenient for programmer debugging. Release is called publishing, which is often optimized so that the program is optimal in code size and running speed so that users are well used.
Debug and Release True Secrets lies in a set of compilation options. The following is listed below (otherwise additional, such as / fd / fo, but the difference is not important, usually don't cause the Release version error, not discussing here)
Debug version:
/ MDD / MLD or / MTD uses Debug Runtime Library (debug version runtime "
/ OD close optimization switch
/ D "_debug" is equivalent to #define _debug, open the compiled debug code switch (mainly for
askERT function)
/ Zi Create Edit and Continue (editing) database, which is debugging
If you modify the source code, you need to recompile.
/ GZ can help capture memory errors
/ GM opens minimized weight link switch, reduce link time
RELEASE version:
/ Md / ml or / mt uses the release version of the runtime function library
/ O1 or / O2 optimize the switch to minimize the program or the fastest
/ D "ndebug" Close condition compiles debug code switch (ie, does not compile Assert function)
/ GF combined repetitive strings and put the string constants in read-only memory to prevent
modified
In fact, Debug and Release have no essential boundaries, they are just a set of compile options, and the compiler is just a scheduled option action. In fact, we can even modify these options to get an optimized debug version or a publishing version with tracking statements.
Second, where the release version is wrong
With the above introduction, let's take a look at these options to see how the Release version is generated.
1. Runtime Library: Which runtime library is usually only impact on the performance of the program. The debug version of Runtime Library contains debugging information and has some protection mechanism to help find errors, so performance is not as good as release. The Runtime Library provided by the compiler is usually very stable and will not cause the Release version of the error; It should be pointed out that if Debug is wrong, even if Release is normal, the program is definitely a bug, but it may be that the release version of the RELASE version is not expressed.
2. Optimization: This is the main reason for errors, because the source program is basically directly translated, while the compiler will make a series of assumptions after opening optimization. Such errors have the following:
(1) Frame Pointer omission (referred to as FPO): During the function call, all call information (return addresses, parameters), and automatic variables are placed in the stack. If the declaration of the function is different (parameters, return value, call mode), an error is generated --- but DEBUG mode, the stack is implemented through the address saved by the EBP register, and if there is no error, the error occurred (Or the crossover "not much"), the function can usually be executed properly; Under the Release mode, the EBP stack base pointer is omitted so that the return address error will cause the return address to crash through a global pointer access stack. C strong type features can check most such errors, but if they use forced type conversion, they will not. You can enforce the Add / Oy-Compile option in the Release version to turn off the frame pointer to determine if this class is. Such errors are usually: ● The MFC message response function is written errors. Correct should be
AFX_MSG LRESULT OnMESSAGEOWN (WPARAM WPARAM, LPARAM LPARAM);
ON_MESSAGE macro contains forced type conversion. One way to prevent this error is to redefine the ON_MESSAGE macro, add the following code to stdafx.h (after #include "afxwin.h"), the function is compiled when the function is wrong.
#undef on_Message
#define on_Message (Message, MemberfxN) /
{Message, 0, 0, 0, AFXSIG_LWL, /
(AFX_PMSG) (AFX_PMSGW) (static_cast CWnd :: *) (WPARAM, LPARAM)> (& MemberfxN)} (2) Volatile type variable: Volatile tells the compiler that the variable may be modified in an unknown manner outside the program (such as system, other processes, and threads). Optimization procedures in order to increase program performance, some variables are often placed in registers (similar to the register keyword), while other processes can only modify the memory where the variable is located, and the value in the register has not changed. If your program is multi-thread, or you find that the value of a variable does not match the expected, you are confident that it is set, it is likely to encounter such problems. This error sometimes manifests the program to optimize the normal optimization in the fastest optimization. Try the VOLATILE that you think is suspicious. (3) Variable Optimization: The optimization procedure optimizes variables according to the use of variables. For example, there is a variable that is unused in the function, which is likely to cover a array base, and in the Release version, this variable is likely to be optimized, and the array crosstation will destroy the data used in the stack. Of course, the actual situation will be much more complicated than this. There are errors related to this: ● Illegal access, including array offline, pointer error, etc. E.g Void Fn (void) { INT I; i = 1; Int a [4]; { Int J; J = 1; } A [-1] = 1; // Of course, the error will not be so obvious, such as the subscript is a variable. a [4] = 1; } J Although the scope has been used in the array of crosses, the space has not been retracted, so I and J will cover the offline. And Release Edition Due to I, J does not have a big role to be optimized, so that the stack is destroyed. 3. _debug and ndebug: When _debug is defined, the assert () function is compiled, while NDebug is not compiled. In addition, there is a series of assertion macros in VC . This includes: ANSI C asserts Void Assert (int Expression); C Runtime LIB assertion_assert (booleaneXpression); _Asserte (booleaneXpression); MFC asserts Assert (BooleaneXpression); Verify (BooleaneXpression); Ask_VALID (POBJECT); Assert_kindof (classname, pObject); ATL asserts Atlassert (BooleaneXpression); In addition, the compilation of the Trace () macro is also controlled by _debug. All of these assertions are only compiled in the Debug version, and it is ignored in the release version. The only exception is verify (). In fact, these macros are calling the assert () function, but there are only some debugging code related to the library. If you add any program code in these macros, not just Boolean expression (such as assigning, you can change the variable value of the variable value), then the Release version does not perform these operations, resulting in an error. Beginners are easy to make such mistakes, the method of finding is also very simple, because these macros have been listed above, as long as the VC Find in Files feature is used to find these macros in all files, then check can. In addition, some masters may also join the criteria compilation of #ifdef _debug, but also pay attention to it. By the way, it is worth mentioning the verify () macro, this macro allows you to put the program code in the Boolean expression. This macro is usually used to check the return value of the Windows API. Some people may abuse verify () for this reason, in fact this is dangerous, because verify () violates the idea of asserting, can't completely separate the program code and debug code, and ultimately may bring a lot of trouble. Therefore, experts recommend that this macro is used as much as possible. 4. / Gz option: This option will do these things (1) Initialize the memory and variables. Including all automatic variables, 0xCD (ie, dynamically assigned memory, such as new), 0xDD (DEAD DATA), 0xFD (DEFENCDE), 0xCD (DEFENCDE), 0xFD (DEFENCDE) DATA) Initializing the protected memory (DEBUG version is added to prevent memory before and after dynamic allocation to prevent offshore access), where the words in the parentheses are a help letter proposed by Microsoft. The benefits of doing this are that these values are very large, and it is impossible as a pointer (and the pointer in the 32-bit system is rarely odd, and the odd pointer in some systems will generate runtime errors), as a few more It is also easy to identify, so this is also very beneficial to find the error that Release version will encounter in the Debug version. It is important to note that many people think that the compiler will use 0 to initialize the variable, which is wrong (and this is very disadvantage). (2) When the function is called, the function call is verified by checking the stack pointer. (Preventing the original formation) (3) The function returns the front inspection stack pointer to confirm that it is not modified. (Prevent Offshore Access and Original Mismatch, with the second one can be rushed to the frame pointer to omit the FPO) usually / gz option causes the Debug version error and the normal phenomenon of the Release version, because the unmelted variables in the release version are randomly It is possible to make the pointer to cover an effective address to cover illegal access. In addition, / GM / GF and other options have less errors, and their effect is obvious, it is easier to find. Third, how to "debug" Release version of the program It is obviously a very frustrated thing to meet the success of Debug but Release failed. If you look at the above analysis, combine the specific performance of the mistake, soon find a mistake, although very good. But if you can't find it for a while, some strategies in this case will be given. 1. Before mentioned, Debug and Release are only the difference in compilation options, and there is no definition that can distinguish between them. We can modify the Release version of the compilation option to narrow the range of error. As mentioned above, the release option can be changed to the opposite DEBUG option, such as / md to / MDD, / O1 to / OD, or run time optimization to program size optimization. Note that only one option is changed once, and if you change which option, the error disappears, and then looks for the error that should be selected. These options can be selected directly in Project / Settings ..., usually do not modify manually. Since the above analysis is quite comprehensive, this method is most effective. 2. When you have the programming process, you should pay attention to the test Release version, so as not to have too many last code, time is very tight. 3. Use the / W4 warning level in the Debug version, which can get the maximum error message from the compiler, such as if (i = 0), will cause / W4 warning. Don't ignore these warnings, usually this is caused by BUG in your program. But sometimes / W4 will bring a lot of redundant information, such as unused function parameters warning, and many messages handlers ignore certain parameters. We can use #Progma Warning (Disable: 4702) // Prohibited // ... #Progma Warning (Default: 4702) // Re-allowed Come temporarily ban a warning, or use #Progma Warning (Push, 3) // Set warning level for / w3 // ... #Progma Warning (POP) // Reset to / W4 To temporarily change the warning level, sometimes you can only use the suspicious part of the code to use / W4. 4. You can also debug your Release version as debug, just join the debug symbol. In Project / Settings ..., select Settings for "Win32 Release", select the C / C label, category selection General, Debug Info, select Program Database. Then, in the LINK tag Project Options, finally, "/ OPT: REF" (quotation marks do not lose). This allows the debugger to use the debug symbols in the PDB file. But when you debug, you will find a breakpoint is difficult to set, and the variable is also difficult to find - these are optimized. Fortunately, the Call Stack window is still working properly, even if the frame pointer is optimized, the stack information (especially the return address) can still be found. This is very helpful for positioning errors.