Differences between Debug and Release versions

Source: Internet
Author: User

Differences between Debug and Release versions

There is no essential difference between Debug and Release. They are just a set of two sets of compilation options provided by VC, And the compiler only acts according to the predefined options. If we want to, we can totally turn the actions of Debug and Release upside down. Of course, you can also provide other modes, such as defining a set of compilation options and naming them as MY_ABC. Traditionally, we prefer to use the name defined by VC.
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 ATL, Debug and Release have similar requirements on DLL. If you use the dynamic MFC Library as the compilation option, you need to support MFC42D. DLL and other libraries. The Release version requires the support of MFC42.DLL. Release does not Debug the source code. It does not take into account the MFC diagnostic macro. It uses the MFC Release library to optimize the application speed during compilation, while Debug is the opposite, it allows debugging of source code, defines and uses the diagnostic macro of MFC, and uses the Debug library of MFC, which does not optimize the speed.
Since Debug and Release are only different compilation options, why should we differentiate Debug and Release versions?
Debug and Release, in my opinion, are primarily differentiated based on their specific targets. Debug is usually called a debugging version. With the combination of a series of compilation options, the compilation results usually contain debugging information without any optimization, providing developers with powerful application debugging capabilities. Release is usually called a Release version and is intended for users. Generally, users are not allowed to debug the released version. Therefore, the debugging information is not saved. At the same time, it is often optimized to minimize the code and optimize the speed. It facilitates users' usage.

The following is only a comparison of the default Debug and Release options. For details about the compilation options, see the description of MSDN.
We compare the default Debug and Release options to filter out the same settings. The main differences are as follows:
Compilation options:/Od/D "_ DEBUG"/Gm/RTC1/MDd/Fo "Debug" "/ZI
Link options:/OUT: "D:" MyProject "logging" Debug "OptionTest. dll"/INCREMENTAL
Release settings:
Compilation options:/O2/GL/D "NDEBUG"/FD/MD/Fo "Release"/Zi
Link options:/OUT: "D:" MyProject "logging" Release "OptionTest. dll"/INCREMENTAL: NO

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 for the assert function)
/ZI creates the Edit and continue database. If the source code is modified during debugging, you do not need to re-compile the database.
/GZ helps capture Memory Errors
/Gm enables the minimize reconnection switch to reduce the link time
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 repeat strings and puts string constants in read-only memory to prevent modification.

MDd and MD
First, the Debug version uses the Debug version's Runtime Library (/MDd option), and The Relase version uses the released version's Runtime Library (vcrt. dll ). The main difference is the performance impact during running. The Runtime Library of the debug version contains debugging information and uses some protection mechanisms to help identify errors. Therefore, its performance is inferior to that of the released version. The Runtime Library provided by the compiler is very stable and will not cause Release version errors. The Debug version's Runtime Library enhances error detection, such as heap memory allocation check. Instead, it reports errors, it should be noted that if Debug has errors and the Release version is normal, the program must have bugs, but we have not found them yet.
ZI and Zi
Second, the/ZI option and/Zi option. By using the/ZI option, you can modify the code during the debugging process without re-compiling. This is a good helper for debugging, but if we use the Release version, this will become unavailable.

Od and O2
/O2 and/Od options: Od is used to disable Compiler Optimization and is widely used in Debug versions. The O2 option is the fastest way to create code, which is of course the best choice for the Release version.

RTCx
The/RTCx option allows the compiler to insert dynamic detection code to help you detect errors in the program. For example, it initializes a local variable to a non-zero value. Including using 0xCC to initialize all automatic variables, 0xCD to initialize memory allocated in the heap (I .e. new memory), and 0xDD to fill the released memory (I .e. delete memory ), 0xFD initializes the protected memory (debug adds the protected memory before and after the dynamically allocated memory to prevent cross-border access ). The advantage of doing so is that these values are very large and generally cannot be used as pointers, exams, and big tips are rarely used as values, and these values are easy to recognize, therefore, it is helpful to find the Release version errors. In addition, when a function is called through the function pointer, the matching of the function call is verified by checking the stack pointer (to prevent the prototype mismatch ). When the/RTCx option is used, debugging version errors may occur, while the Release version is normal. Because uninitialized variables in the Release version are random, it is likely that the pointer points to a valid but incorrect address, this masks errors. This compilation option can only be used under the/Od option.

Gm, INCREMENTAL or NO
The Gm in the compilation option and the INCREMENTAL in the Link option are only for one purpose, speeding up compilation. We often encounter this problem. Only one header file is modified, but all dynamic libraries are recompiled. These two options are used to solve the problem. If the/Gm switch is enabled, the compiler stores the dependency between the source file and the class definition in the. idb file of the project. In the subsequent compilation process, use the information in the. idb file to determine whether to compile a source file, even if the source file already contains the modified. h file.
The INCREMENTAL switch is enabled by default. The executable files generated by using incremental links or the dynamic link library will be larger than the programs generated by non-incremental links because of code and data filling. In addition, the incremental link file also contains a jump to the trunk to relocate the processing function to the new address.
MSDN clearly states that to ensure that the final release version does not contain a fill or trunk, please do not add a link program.

/GZ option: do the following:
1. Initial 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 (for example, delete), 0xFD (deFencde Data) initialize protected memory (the debug version adds protected internal memory before and after dynamic memory allocation to prevent cross-border access). The words in brackets are the mnemonic words recommended 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, this is very helpful for the Release of Release in the Debug version. 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 the error ).
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)

Usually, the/GZ option 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.

_ DEBUG and NDEBUG
This is the most important option. The two are pre-processor definitions of the compiler. By default, _ DEBUG is used for the Debug version, while NDEBUG is used for the Release version. They can be said to be important. Because assert series assertions only take effect under _ DEBUG!
The following are extracted from the assert. h file:
C ++ code
# Ifdef NDEBUG
# Define assert (_ Expression) (void) 0)
# Else/* NDEBUG */
# Ifdef _ cplusplus
Extern "C "{
# Endif/* _ cplusplus */
_ Cribd void _ cdecl _ wassert (_ in_z const wchar_t * _ Message, _ in_z const wchar_t * _ File, _ in unsigned _ Line );
# Ifdef _ cplusplus
}
# Endif/* _ cplusplus */
# Define assert (_ Expression) (void )((!! (_ Expression) | (_ wassert (_ CRT_WIDE (# _ Expression), _ CRT_WIDE (_ FILE _), _ LINE _), 0 ))
# Endif/* NDEBUG */

# Ifdef NDEBUG
# Define assert (_ Expression) (void) 0)
# Else/* NDEBUG */
# Ifdef _ cplusplus
Extern "C "{
# Endif/* _ cplusplus */
_ Cribd void _ cdecl _ wassert (_ in_z const wchar_t * _ Message, _ in_z const wchar_t * _ File, _ in unsigned _ Line );
# Ifdef _ cplusplus
}
# Endif/* _ cplusplus */
# Define assert (_ Expression) (void )((!! (_ Expression) | (_ wassert (_ CRT_WIDE (# _ Expression), _ CRT_WIDE (_ FILE _), _ LINE _), 0 ))
# Endif/* NDEBUG */

It can be seen that when _ DEBUG is not defined, assert becomes an empty statement and is not executed.
That is to say, we cannot use the assertion mechanism for program debugging for all currently released versions.

Related Experience:
1. variables.
As we all know, the operations performed by debug and release when initializing variables are different. debug assigns each byte to 0xcc, and the value assignment of release is similar to random. If a variable in your program is referenced without being initialized, an exception is likely to occur: being used as a control variable will lead to inconsistent process orientation; 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. So it is the easiest and most effective way to initialize a default value for a variable immediately after declaring it. Otherwise, there is no place to find it when the project is too large. Code errors may be ignored and not noticed in debug mode. In the debug mode, most arrays do not go out of bounds and are exposed in the release, which is difficult to find.
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. Is there a problem with debug and release? The answer is yes. When declaring the function body of a custom message, you will often see the following statement: afx_msg LRESULT OnMessageOwn (); In Debug mode, there will generally be no problems, however, when you use a message in a multi-thread or process in a Release environment, it will lead to errors such as invalid handles. The direct cause of this error is that the message body parameter is not added, that is, it should be written to: afx_msg LRESULT OnMessageOwn (WPARAM wparam, LPARAM lparam); 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 view the source code of MFC and find many ASSERT statements (assertions). This macro is only valid in debug mode, it is clear that the release version does not report errors because it ignores errors rather than no errors. This may pose a major risk because it is easier to Debug in Debug mode, check your code, and I will not talk about it more.
3. ASSERT, VERIFY, TRACE ...... debug macro
This situation can be easily explained. For example, enter ASSERT under VC and select F12 to jump to the macro-defined place. Here you can find that ASSERT in Debug needs to execute AfxAssertFailedLine, the macro definition in 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.

Under what circumstances will the Release version go wrong?
1. Runtime Library: Specifies the Runtime function Library to be linked, which usually only affects the performance of the program. 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. Instead, 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 bugs, but it may be that a certain running 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 occurs. However, in the Debug mode, stack access is implemented through the address saved by the EBP register, if there are no errors such as array out-of-bounds (or not many), the function can normally be executed. In the Release mode, optimization will omit the base address pointer of the EBP stack, 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. Correct should be
Afx_msg LRESULT OnMessageOwn (WPARAM wparam, LPARAM lparam );
ON_MESSAGE macro contains forced type conversion. One of the methods to prevent this error is to redefine the ON_MESSAGE macro and add the following code to stdafx. h (after # include "afxwin. h"). An error will be reported during compilation of the function prototype errors.
C ++ code
# 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 )},

# 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
C ++ code
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;
}

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 disconnected void assert (int expression );
C Runtime Lib disconnected _ ASSERT (booleanExpression );
_ ASSERTE (booleanExpression );
Mfc assert (booleanExpression );
VERIFY (booleanExpression );
ASSERT_VALID (pObject );
ASSERT_KINDOF (classname, pobject );
ATLASSERT (booleanExpression );
In addition, the compilation of TRACE () macros 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. Beginners are easy 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 the VERIFY () Macro, which allows you to put program code in a Boolean expression. This macro is usually used to check the return values of Windows APIs. Some 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.

I. "Debug is a debugging version, including more program information"
Supplement: Only DEBUG programs can set breakpoint, single-step execution, and DEBUG output statements using TRACE/ASSERT. Realbench does not contain any debugging information, so it is small in size and runs fast.

I. Memory Allocation Problems
1. The variable is not initialized. The following program runs well in debug.
C ++ code
Thing * search (thing * something)
BOOL found;
For (int I = 0; I <whatever. GetSize (); I ++)
{
If (whatever [I]-> field = something-> field)
{/* Found it */
Found = TRUE;
Break;
}/* Found it */
}
If (found)
Return whatever [I];
Else
Return NULL;

Thing * search (thing * something)
BOOL found;
For (int I = 0; I <whatever. GetSize (); I ++)
{
If (whatever [I]-> field = something-> field)
{/* Found it */
Found = TRUE;
Break;
}/* Found it */
}
If (found)
Return whatever [I];
Else
Return NULL;

But not in release, because in debug, found = FALSE is automatically initialized for the variable, but not in release. Initialize variables, classes, or structures as much as possible.

2. Data Overflow
For example:
C ++ code

Char buffer [10];
Int counter;
Lstrcpy (buffer, "abcdefghik ");


Char buffer [10];
Int counter;
Lstrcpy (buffer, "abcdefghik ");

In the debug version, the buffer's NULL overwrites the counter's high position, but unless counter> 16 M, there is no problem. However, in the release version, counter may be placed in the register, so that NULL overwrites the space in the buffer, which may be the return address of the function, leading to access error.

3. The memory allocation methods for DEBUG and RELEASE versions are different. If you apply for 6 * sizeof (DWORD) = 24 bytes for ele in DEBUG, you are actually allocated 32 bytes (32bytes for debug ), in the release version, 24 bytes are allocated to you (8 bytes for the release version). Therefore, if you write ele [6] In the debug version, there may be no problems, in the release version, access violate exists.

II. ASSERT and VERIFY

1. ASSERT will not be compiled in the Release version.

The ASSERT macro is defined in this way.
C ++ code

# Ifdef _ DEBUG
# Define ASSERT (x) if (x) = 0) report_assert_failure ()
# Else
# Define ASSERT (x)
# Endif


# Ifdef _ DEBUG
# Define ASSERT (x) if (x) = 0) report_assert_failure ()
# Else
# Define ASSERT (x)
# Endif

Actually complicated, but irrelevant. If you add the Code required by the program to these statements
For example
C ++ code

ASSERT (pNewObj = new CMyClass );

PNewObj-> MyFunction ();


ASSERT (pNewObj = new CMyClass );

PNewObj-> MyFunction ();

In this case, pNewObj in the Release version is not allocated to space.

Therefore, when the next statement is executed, the program reports that the program has performed illegal operations. In this case, you can use VERIFY:
C ++ code

# Ifdef _ DEBUG
# Define VERIFY (x) if (x) = 0) report_assert_failure ()
# Else
# Define VERIFY (x)
# Endif


# Ifdef _ DEBUG
# Define VERIFY (x) if (x) = 0) report_assert_failure ()
# Else
# Define VERIFY (x)
# Endif

In this way, the code can be executed in the release version.

III. Parameter issues:

The custom message processing function must be defined as follows:
Afx_msg LRESULT OnMyMessage (WPARAM, LPARAM );
The returned value must be HRESULT type. Otherwise, the Debug will pass, and the Release will fail.

IV. Memory Allocation
Ensure uniformity of Data creation and clearing: If a DLL provides a function that can create data, the DLL should also provide a function to destroy the data. Data creation and cleanup should be at the same level.

V. DLL disaster
People refer to the inconsistency image caused by the mix of different versions of DLL called "the Hell of dynamic Connection Library" (DLL Hell), and even Microsoft itself said so http://msdn.microsoft.com/library/techart/dlldanger1.htm ).

If your program uses your own DLL, note the following:

1. You cannot mix debug and release DLL versions. Both debug and release versions are release.
The solution is to put the debug and release programs under the debug and release directories of the main program respectively.

2. Never think that static connection to the database will solve the problem, which will only make the situation worse.

Debugging in VI. RELEASE:
1. Change ASSERT () to VERIFY (). Find the code defined in "# ifdef _ DEBUG". If you need the code in the RELEASE version, move it out of the definition. Find the code in TRACE (...) because the code is not compiled in RELEASE. Check whether the Code required in the RELEASE is not cheap.
2. The differences brought about by variable initialization exist in different systems or between DEBUG/RELEASE versions. Therefore, initialize the variables.
3. Is there a warning during compilation? Set the warning level to 3 or 4, and ensure that no warning appears during compilation.

VII. Change the optimization option under the "C ++/C" Project in Project Settings to Disbale (Debug ). Compiler Optimization may cause many unexpected errors, please refer to the http://www.pgh.net /~ Newcomer/debug_release.htm

1. 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"

Some restrictions arising from this practice:

The value of the variable in the mfc dll cannot be obtained.

All DLL projects used by the software must be modified.

In addition:

1. ms bug: a ms technical document 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.

2. http://www.sysinternals.com/there is a program DebugView, which is used to capture output of OutputDebugString. After running it (it is estimated that it is set to system debugger), you can view output of OutputDebugString of all programs. After that, you can run your program and view debugging information without using VC.

3. There is a static code check tool named Gimpel Lint, it is said that it is better to use http://www.gimpel.com/but to convert $.

Different Problems With Debug and Release often occur at the beginning of code writing. 99% is caused by Incorrect code writing. Therefore, do not say that the system questions or compiler questions are not moved, the reason for trying to find yourself is the root cause. I used to encounter this situation. I started to pay attention to it after I had learned it again and again. Now I haven't encountered this kind of question in the code I have written 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 and array variables (in large cases, another consideration is taken ).
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.

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.