How can I prevent GCC from eliminating the code inside if(0) block?
When I use Visual Studio, one of my debugging techniques is to put code like this in my program:
if (0)
do_some_debug_printing_and_checking();
Then, when a breakpoint is hit, I click at the do_some_debug_printing_and_checking() line, select "set next statement" and force it to execute.
When I use gcc/gdb as a back-end, the "set next statement" does not work anymore, as GCC simply removes the code from inside the if(0) statement.
I am of course using the -O0 flag to disable optimization. I have also tried the -fno-dce -fno-tree-dce flags to disable dead code elimination explicitly, but it has no effect: the contents of if(0) is just not present in the binary file and I cannot use set next statement to jump into it.
Is there any good way to tell gcc to disable elimination of if(0) contents?
Edit:
Thanks for the "additional variable" workaround, however there are 2 things I don't like about it:
Really, there's absolutely no option to make GCC keep that dead code?
The simplest thing to do is to make the check depend on (say) a variable with external linkage.
E.g.
extern bool debug;
if (debug)
do_some_debug_printing_and_checking();
The somewhere at namespace scope:
bool debug = false;
I would not rely on gcc compiler flags to do this. Compiler flags can change across versions of gcc, and do change across compilers. You may find yourself needing to debug the same code in six months in Visual C++...
@CharlesBailey makes a nice suggestion for how to do this with an extern
variable. Here's one alternative that doesn't require a variable to be exposed to the entire module or kept in static storage.
Declare a temporary variable volatile
in the scope of the if
statement:
if (volatile bool dbg = false)
{
do_some_debug_printing_and_checking();
}
This keeps the scope of the temporary variable quite narrow. The volatile
qualifier does not let the compiler assume anything about the variable, or optimize the branch away.
One thing to keep in mind is that the variable is always allocated on the stack, and will be kept on the stack until the function exits. Both this approach and the extern
approach should work, but have slightly different (and probably negligible) tradeoffs.
If you're willing to use macros to help solve this problem, then you can easily disable the temporary variable when your release your code into production:
#ifndef IS_DEBUGGING
# define IS_DEBUGGING 0
#endif
#if IS_DEBUGGING
# define TMP_DBG_FLAG volatile bool dbg_flag = false
#else
# define TMP_DBG_FLAG false
#endif
Then declare your if
statement as:
if ( TMP_DBG_FLAG )
{
do_some_debug_printing_and_checking();
}
When you define IS_DEBUGGING to be 1, the local variable is created, declared volatile, and kept. When you define IS_DEBUGGING to be 0, the macro expands to the constant false
and the compiler optimizes the branch away. Something very similar could be done for the extern
approach, as well.
This few extra lines of code, but they're independent of the number of times you use TMP_DBG_FLAG. The code is also a lot more readable than using tons of ifdef
s. The macro could be made a bit safer (by appending the value of __LINE__
to it), but this would require three macros, and is probably not necessary:
#if IS_DEBUGGING
// paste symbols 'x' and 'y' together
# define TMP_DBG_FLAG_SYMCAT0(x,y) x ## y
// need one level of indirection to expand __LINE__...
# define TMP_DBG_FLAG_SYMCAT(x,y) TMP_DBG_FLAG_SYMCAT0(x,y)
# define TMP_DBG_FLAG volatile bool TMP_DBG_FLAG_SYMCAT(dbg_flag_,__LINE__) = false
#else
# define TMP_DBG_FLAG false
#endif
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With