Optimization breaks the simple one-to-one correspondence between source lines and machine instructions that a debugger relies on. At -O2 the compiler reorders instructions, inlines functions (so they have no separate frame), keeps variables in registers or eliminates them entirely, and merges or removes code, so GDB shows confusing behavior: stepping jumps around non-sequentially or backwards, breakpoints land on unexpected lines or can't be set on optimized-away code, and inspecting a variable yields <value optimized out> because it no longer has a stable memory/register location at that point. The normal handling is to build your debug configuration with -Og, which enables optimizations that don't interfere with debugging (or -O0 for fully literal stepping), and always with -g for symbols, giving you sane line-by-line stepping and full variable visibility. The important caveat is that some bugs only manifest under optimization, typically undefined behavior that the optimizer exploits (signed overflow, strict aliasing, uninitialized reads), or timing/size differences, so you can't always "just turn off optimization": the bug disappears at -O0. In those cases you debug the optimized build anyway, leaning on the disassembly view, register inspection, and reasoning about what the optimizer did, and you treat the disappearing-at-O0 behavior itself as a strong signal of UB to hunt down in the source. So the answer is -Og/-g for routine debugging, but be ready to debug optimized code when the bug is optimization-dependent.
Debugging & Toolchain · Interview question
Why is debugging optimized code harder, and how do you handle it?
A strong answer
What a weak answer sounds like
You know the answer. Do you know what gets you dinged?
Pro breaks down the answer most candidates actually give to this question — and the specific reason an interviewer marks it down. It’s the difference between sounding correct and sounding senior, on all 472 questions.
From the lesson
Debugging with GDB
Pause, inspect, and step through a running program: GDB's core commands (break/continue/step, print, backtrace), connecting to an embedded target over a gdbserver, and the optimization gotcha.