Source variables do not always have storage
An optimized-out value may have been replaced by a constant, combined with another expression, or kept in a register only for part of execution. The compiler does not have to provide a distinct memory location for every source variable. The running program consists of generated instructions, not the source text itself. A value unavailable under its source name is therefore not proof of missing initialization. Check how the executable was built before interpreting the debugger display.
Separate observation builds from reproduction builds
For learning on a small example, -g -O0 can make the relation between source and instructions easier to follow. Turning optimization off is less useful if a production failure only appears with optimization enabled: the change may remove the very conditions being investigated. Debug information and optimization are not mutually exclusive, and GCC also provides -Og for debugging-oriented optimization. Keep the original failing build conditions and record every changed option. Do not mix observations from different builds as though they were one execution.
Explain unexpected source-line movement
Optimizers can combine operations, move work outside loops, or inline calls. Source-level stepping may skip lines or revisit them, and an expected separate stack frame may not exist. DBG Desk steps through actual machine instructions, allowing branches and data movement to be inspected, but matching an instruction to a source expression still depends on the available debug information. Read address changes and stack context together rather than treating unusual line movement as evidence of broken control flow.
Look at observable boundaries
If a local value cannot be inspected, compare the function’s inputs and outputs. Registers around a call, output buffers, or externally visible results can narrow a calculation without exposing every intermediate source variable. A reduced reproduction should preserve relevant types and compiler settings. Adding volatile simply to make a variable visible changes optimization and is not a general correction. Clearly distinguish evidence from the original failure from evidence obtained under easier observation conditions.
Keep the two binaries separate
Store observation and reproduction builds in distinct directories with their compiler options and inputs. Compare final behavior as well as names or stack layouts. A failure disappearing after a rebuild is not a diagnosis; it is a clue about the changed conditions. Use it to form a narrower hypothesis about generated code or memory layout.
gcc -g -O0 example.c -o example-debug.exe
gcc -g -O2 example.c -o example-optimized.exe