How to: Debug Optimized Code
Applies to: Visual Studio Visual Studio for Mac
Note
This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here
Note
The dialog boxes and menu commands you see might differ from those described in Help depending on your active settings or edition. To change your settings, choose Import and Export Settings on the Tools menu. For more information, see Reset settings.
Note
The /Zo (Enhance Optimized Debugging)compiler option (introduced in Visual Studio Update 3) generates richer debugging information for optimized code (projects that are not built with the /Od compiler option. See /O Options (Optimize Code)). This includes improved support for debugging local variables and inlined functions.
Edit and Continue is disabled when the /Zo ocompiler option is used.
When the compiler optimizes code, it repositions and reorganizes instructions. This results in more efficient compiled code. Because of this rearrangement, the debugger cannot always identify the source code that corresponds to a set of instructions.
Optimization can affect:
Local variables, which can be removed by the optimizer or moved to locations the debugger does not understand.
Positions inside a function, which are changed when the optimizer merges blocks of code.
Function names for frames on the call stack, which might be wrong if the optimizer merges two functions.
The frames that you see on the call stack are almost always correct, however, assuming you have symbols for all frames. The frames on the call stack will be wrong if you have stack corruption, if you have functions written in assembly language, or if there are operating system frames without matching symbols on the call stack.
Global and static variables are always shown correctly. So is structure layout. If you have a pointer to a structure and the value of the pointer is correct, every member variable of the structure will show the correct value.
Because of these limitations, you should debug using an unoptimized version of your program if at all possible. By default, optimization is turned off in the Debug configuration of a C++ program and turned on in the Release configuration.
However, a bug might appear only in an optimized version of a program. In that case, you must debug the optimized code.
To turn on optimization in a Debug build configuration
When you create a new project, select the
Win32 Debug
target. Use theWin32 Debug
target until your program is fully debugged and you are ready to build aWin32 Release
target. The compiler does not optimize theWin32 Debug
target.Select the project in Solution Explorer.
On the View menu, click Property Pages.
In the Property Pages dialog box, make sure
Debug
is selected in the Configuration drop-down list.In the folder view on the left, select the C/C++ folder.
Under the C++ folder, select
Optimization
.In the properties list on the right, find
Optimization
. The setting next to it probably saysDisabled (
/Od)
. Choose one of the other options (Minimum Size``(
/O1)
,Maximum Speed``(
/O2)
,Full Optimization``(
/Ox)
, orCustom
).If you chose the
Custom
option forOptimization
, you can now set options for any of the other properties shown in the properties list.Select the Configuration Properties, C/C++, Command Line node of the project properties page, and add
(
/Zo)
to the Additional Options text box.Warning
/Zo
requires Visual Studio 2013 Update 3 or a later version.Adding
/Zo
will disable Edit and Continue.When you debug optimized code, use the Disassembly window to see what instructions are actually created and executed. When you set breakpoints, you need to know that the breakpoint might move together with an instruction. For example, consider the following code:
for (x=0; x<10; x++)
Suppose you set a breakpoint at this line. You might expect the breakpoint to be hit 10 times, but if the code is optimized, the breakpoint is hit only one time. That is because the first instruction sets the value of x
to 0. The compiler recognizes that this only has to be done once and moves it out of the loop. The breakpoint moves with it. The instructions that compare and increment x
remain inside the loop. When you view the Disassembly window, the step unit is automatically set to Instruction for greater control, which is useful when you step through optimized code.