Search code examples
c++c

Why does a C/C++ program often have optimization turned off in debug mode?


In most C or C++ environments, there is a "debug" mode and a "release" mode compilation.
Looking at the difference between the two, you find that the debug mode adds the debug symbols (often the -g option on lots of compilers) but it also disables most optimizations.
In "release" mode, you usually have all sorts of optimizations turned on.
Why the difference?


Solution

  • Without any optimization on, the flow through your code is linear. If you are on line 5 and single step, you step to line 6. With optimization on, you can get instruction re-ordering, loop unrolling and all sorts of optimizations.
    For example:

    
    void foo() {
    1:  int i;
    2:  for(i = 0; i < 2; )
    3:    i++;
    4:  return;
    

    In this example, without optimization, you could single step through the code and hit lines 1, 2, 3, 2, 3, 2, 4

    With optimization on, you might get an execution path that looks like: 2, 3, 3, 4 or even just 4! (The function does nothing after all...)

    Bottom line, debugging code with optimization enabled can be a royal pain! Especially if you have large functions.

    Note that turning on optimization changes the code! In certain environment (safety critical systems), this is unacceptable and the code being debugged has to be the code shipped. Gotta debug with optimization on in that case.

    While the optimized and non-optimized code should be "functionally" equivalent, under certain circumstances, the behavior will change.
    Here is a simplistic example:

        int* ptr = 0xdeadbeef;  // some address to memory-mapped I/O device
        *ptr = 0;   // setup hardware device
        while(*ptr == 1) {    // loop until hardware device is done
           // do something
        }
    

    With optimization off, this is straightforward, and you kinda know what to expect. However, if you turn optimization on, a couple of things might happen:

    • The compiler might optimize the while block away (we init to 0, it'll never be 1)
    • Instead of accessing memory, pointer access might be moved to a register->No I/O Update
    • memory access might be cached (not necessarily compiler optimization related)

    In all these cases, the behavior would be drastically different and most likely wrong.