Essential differences between debug and release compilation methods

Source: Internet
Author: User

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 (runtime function library of the debug version)/OD to disable the optimization switch/D "_ debug" is equivalent to # DEFINE _ debug, enable the compile and debug code switch (mainly for the assert function)/Zi to create the edit and continue database, in this way, if the source code is modified, you do not need to re-compile/GZ, which can help capture memory errors/enable the minimal re-link switch on GM, reducing the link time. Release Version: /MD/ml or/MT use the release version of the runtime function library/O1 or/O2 optimization switch, minimal or fastest Program/D "ndebug" Disable Conditional compilation and debugging code switch (I .e., do not compile assert function)/GF merge duplicate strings, and put string constants in read-only memory, 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. 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 produced. 1. Runtime Library: Which runtime function library is linked usually only affects program performance. The Runtime Library of the debug version contains debugging information and uses some protection mechanisms to help identify errors. Therefore, the performance is inferior to that of the release version. The Runtime Library provided by the compiler is usually stable and does not cause release errors. However, the debug Runtime Library enhances error detection, such as heap memory allocation, sometimes there may be debug errors but release is normal. 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 is not 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 (FPO for short): All call information (return address, parameters) and automatic variables are stored in the stack during function call. If the declaration and implementation of a function are different (parameters, return values, and call methods), an error is generated. However, in debug mode, stack access is implemented through the address saved by the EBP register, if no errors such as array out-of-bounds (or "not many" out-of-bounds) occur, the function can normally be executed. In the release mode, optimization will omit the EBP stack base address pointer, in this way, accessing the stack through a global pointer will cause the program to crash if the returned address is incorrect. The strong type feature of C ++ can check the majority of such errors, but if forced type conversion is used, it will not work. You can force the/Oy-compilation option in the release version to disable frame pointer omitting to determine whether such errors are possible. Common Errors include: ● An error occurred while writing the message response function of MFC. The correct value 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 (in # include "afxwin. H "later), the compilation will report an error when the function is incorrect. # 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 to the Register keyword), while other processes can only modify the memory where the variable is located, but the value in the Register remains unchanged. If your program is multi-threaded, or you find that the value of a variable is inconsistent with the expected value and you are sure that the setting is correct, you may encounter such a problem. This type of error is sometimes manifested as the program has the fastest optimization error and the smallest optimization is normal. Add volatile to the variables you think are suspicious. (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 the debug version, it may mask an array out of bounds. In the release version, this variable may be optimized, in this case, the array out-of-bounds will destroy the useful data in the stack. Of course, the actual situation is much more complicated than this. Related errors include: ● illegal 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 the variable A [4] = 1;} J, although it has a scope when the array is out of bounds, its space is not reclaimed, therefore, I and J will overwrite the border. 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 asserted _ assert (booleanexpression); _ asserte (booleanexpression); MFC asserted assert (booleanexpression); Verify (booleanexpression ); assert_valid (pobject); assert_kindof (classname, pobject); ATL asserted atlassert (booleanexpression); in addition, the compilation of the trace () macro is also controlled by _ debug.

All these assertions are compiled only in the debug version, but are ignored in the release version. The only exception is verify (). In fact, these macros call the assert () function, but attach some library-related debugging code. If you add any program code to these macros, instead of a Boolean expression (for example, a value assignment or a function call that can change the value of a variable), the release version will not perform these operations, this may cause errors. It is easy for beginners to make such mistakes, and the search method is also very simple, because these macros are listed above, you only need to use the find in files function of VC ++ to find the place where these macros are used in all files of the project and then check them one by one. In addition, some experts may also add Conditional compilation such as # ifdef _ Debug. Pay attention to it. By the way, it is worth mentioning that the verify () macro allows you to put program code in a Boolean expression. This macro is usually used to check the return values of Windows APIs. Some people may abuse verify () For this reason. In fact, this is dangerous because verify () violates the idea of assertions and cannot completely separate program code from debugging code, in the end, it may cause a lot of trouble. 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 using 0xcc to initialize all automatic variables, 0xcd (cleared data) to 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), and initialize the protected memory (debug adds the protected memory before and after the dynamically allocated memory to prevent cross-border access ), the words in the brackets are the notes suggested by Microsoft. The advantage of doing so is that these values are very large and cannot be used as pointers (and in 32-bit systems, pointers are rarely odd values, in some systems, odd-number pointers produce runtime errors), which are rarely used as numerical values, and these values are easy to recognize, therefore, it is helpful to find the release version errors. Note that many people think that the compiler will use 0 to initialize the variable, which is wrong (and this 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. (To prevent original form mismatch) (3) Check the stack pointer before returning the function 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 common/GZ option will cause 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.

Discussion on essential differences between debug and Release 1. essential differences between debug and release compilation methods debug is usually called a debug version, which contains debugging information without any optimization, it is easy for programmers to debug programs. 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:/md d/MLD or/MTD use the debug Runtime Library (the runtime function library of the debug version)/OD to disable the optimization switch/D "_ debug" is equivalent to # DEFINE _ debug, enable the compile and debug code switch (mainly for the assert function)/Zi to create the edit and continue database, in this way, if the source code is modified during the debugging process, you do not need to re-compile/GZ to help capture memory errors/enable the minimal re-link switch on GM to reduce the link time. Release Version: /MD/ml or/MT use the release version of the runtime function library/O1 or/O2 optimization switch, minimal or fastest Program/D "ndebug" to turn off the Conditional compilation and debugging code switch (that is, do not compile ass ERT function)/g f combines repeated 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. Ii. Under what circumstances will the release version go wrong with the above introduction, let's compare these options one by one to see how the release version errors are produced 1. runtime Library: Specifies the runtime function library to be linked, which usually only affects the program performance. The Runtime Library of the debug version contains debugging information and uses some protection mechanisms to help identify errors. Therefore, the performance is inferior to that of the release version. The Runtime Library provided by the compiler is usually stable and does not cause release errors. However, the debug Runtime Library enhances error detection, such as heap memory allocation, sometimes there may be debug errors but release is normal. 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 is not 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. These errors mainly include: (1) frame pointer (FPO): All call information (return address and parameter) during function calling) and automatic variables are placed in the stack. If the declaration and implementation of a function are different (parameters, return values, and call methods), an error is generated. However, in debug mode, stack access is implemented through the address saved by the EBP register, if no errors such as array out-of-bounds (or "not many" out-of-bounds) occur, the function can normally be executed. In the release mode, optimization will omit the EBP stack base address pointer, in this way, accessing the stack through a global pointer will cause the program to crash if the returned address is incorrect. The strong type feature of C ++ can check the majority of such errors, but if forced type conversion is used, it will not work. You can force the/Oy-compilation option in the release version to disable frame pointer omitting to determine whether such errors are possible. Common Errors include: ● An error occurred while writing the message response function of MFC. The correct value 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 (in # include "afxwin. H "later), the compilation will report an error when the function is incorrect. # 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 to the Register keyword), while other processes can only modify the memory where the variable is located, but the value in the Register remains unchanged. If your program is multi-threaded, or you find that the value of a variable is inconsistent with the expected value and you are sure that the setting is correct, you may encounter such a problem. This type of error is sometimes manifested as the program has the fastest optimization error and the smallest optimization is normal. Add volatile to the variables you think are suspicious. (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 the debug version, it may mask an array out of bounds. In the release version, this variable may be optimized, in this case, the array out-of-bounds will destroy the useful data in the stack. Of course, the actual situation is much more complicated than this. Related errors include: ● illegal 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 the variable A [4] = 1;} J, although it has a scope when the array is out of bounds, its space is not reclaimed, therefore, I and J will overwrite the border. 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 asserted _ assert (booleanexpression); _ asserte (booleanexpression); MFC asserted assert (booleanexpression ); verify (booleanexpression); assert_valid (pobject); assert_kindof (classname, pobject); ATL asserted atlassert (booleanexpression); in addition, the compilation of the trace () macro is also controlled by _ debug. All these assertions are compiled only in the debug version, but are ignored in the release version. The only exception is verify (). In fact, these macros call the assert () function, but attach some library-related debugging code. If you add any program code to these macros, instead of a Boolean expression (for example, a value assignment or a function call that can change the value of a variable), the release version will not perform these operations, this may cause errors. It is easy for beginners to make such mistakes, and the search method is also very simple, because these macros are listed above, you only need to use the find in files function of VC ++ to find the place where these macros are used in all files of the project and then check them one by one. In addition, some experts may also add Conditional compilation such as # ifdef _ Debug. Pay attention to it. By the way, it is worth mentioning that the verify () macro allows you to put program code in a Boolean expression. This macro is usually used to check the return values of Windows APIs. Some people may abuse verify () For this reason. In fact, this is dangerous because verify () violates the idea of assertions and cannot completely separate program code from debugging code, in the end, it may cause a lot of trouble. 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 using 0xcc to initialize all automatic variables, 0xcd (cleared data) to initialize memory allocated in the heap (that is, dynamically allocated memory, such as new), 0xd D (dead data) fill in the released heap memory (such as delete), 0xfd (defencde data), and initialize the protected memory (debug adds the protected memory before and after the dynamically allocated memory to prevent cross-border access ), the words in the brackets are the notes suggested by Microsoft. The advantage of doing so is that these values are very large and cannot be used as pointers (and in 32-bit systems, pointers are rarely odd values, in some systems, odd-number pointers produce runtime errors), which are rarely used as numerical values, and these values are easy to recognize, therefore, it is helpful to find the release version errors. Note that many people think that the compiler will use 0 to initialize the variable, which is wrong (and this 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. (To prevent original form mismatch) (3) Check the stack pointer before returning the function 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 common/GZ option will cause 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. 3. How to "debug" the release version of the program when debugging succeeds but the release fails 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 compilation option of release to narrow down the error range. Note: This article is over now. It seems that there are some other articles that are not in VC when the entire project is large, software often fails to run in the release state when it can run in the debug state. Developers usually develop software in the debug state, so this often happens when we prepare to release the software with confidence after a hard work for a month or two. To avoid unnecessary losses, we 'd better perform the following checks: 1. Often test the two versions of the software. 2. Do not attribute the issue to debug/release unless you have fully tested the two versions. 3. Differences in Preprocessing may also cause such problems. One possibility of a problem is that different pre-processing tags are defined during compilation of different versions. Try the following changes to your debug software: Set the directory (Category) to "general" in C/C ++ in "project setting (ALT-F7 ", and changed "_ de bug" to "ndebug ". set the directory to "Preprocessor" and add definition "_ debug to" undefined Sy mbols "input box. select rebuild all and recompile. if a problem occurs in the compiled program, make the following changes to the Code: Change assert () to verify (). find the code defined in "# ifdef _ debug". If you need the code in the release version, move them out of the definition. Find the code in trace (...) because the code is not compiled in release. Therefore, please carefully check whether the Code required in the release is not cheap. 4. The differences brought about by variable initialization exist between different systems or debug/release versions. Therefore, initialize the variables. 5. Is there a warning during compilation? Set the warning level to 3 or 4, and ensure that no warning appears during compilation. 6. Whether the resource file has been changed. 7. You can also debug the software of the release version. Make the following changes: set "category" to "general" under "Project Settings" C ++/C "and" debug info "to" program database ". select the "Generate debug info" check box under the "Link" project. "Rebuild all" has some restrictions: the value of the variable in the mfc dll cannot be obtained. All DLL projects used by the software must be modified. Also: ms bug: A technical document in MS shows that the "maximize speed" optimization option for DLL in vc5 is not fully supported, therefore, this will cause memory errors and cause program crashes.

Essential differences between debug and release compilation methods

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.