1

Question is related to release and debug build. Something related to this and this

But I have a simple doubt for example if I do following: (file is debug-test.c)

#include <stdio.h>

#define debug  1

int sum (int a, int b){

  if (debug){
    if (a > 0 && b > 0){
      fprintf (stderr, "a(%d) >0 && b(%d)\n", a,b);
    }
  }
  return (a+b);
}

int main (void){

  int a = 10, b = 5;
  printf ("a:%d + b:%d = %d\n", a, b, sum(a,b));
  
  return 0;
}

So my doubt/question is if I do #define debug 0 will compiler eliminate/optimize out all the code (that if condition) from final binary? Or code will remain in final binary as

if (0){
   .....
}

I have lots of testing and other code that just checks execution in various logical conditions.

What I tried is using gcc -S -Wall -Wextra debug-test.c once with debug set to 0 and once debug set to 1.

With debug set to 1 I get something like following:

        .file   "debug-test.c"
        .text
        .section        .rodata
.LC0:
        .string "a(%d) >0 && b(%d)\n"
        .text
        .globl  sum
        .type   sum, @function
sum:
.LFB0:
        .cfi_startproc

When I set debug to 0 I get following


       .file   "debug-test.c"
        .text
        .globl  sum
        .type   sum, @function
sum:
.LFB0:
        .cfi_startproc

I do not really understand output of -S but cursory glance shows that .string "a(%d) >0 && b(%d)\n" is not present when I set debug to 0. Other simple thing that I checked is wc -l debug-test.s so for 0 it gives me 61 lines and for 1 it gives me 78 lines. I am not sure I really understand what is happening, will compiler eliminate code or keep it in binary?

Aval Sarri
  • 198
  • 2
  • 13

2 Answers2

4

Any reasonable behaving compiler will optimize everything away when you define debug to zero. However, there is no guarantee so a better solution is:

#ifdef debug
    if (a > 0 && b > 0){
      fprintf (stderr, "a(%d) >0 && b(%d)\n", a,b);
    }
#endif
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • OP defines `debug` as `0` or `1`, so that should be `#if debug`. – Ian Abbott Sep 27 '21 at 13:21
  • 3
    In some codebases I've worked on, we deliberately chose to rely on the compiler optimizing out `if (0) { ... }`, rather than use preprocessor conditions, because that way the code inside the condition would always be _parsed_ and checked for syntax errors, and it was less likely to bit-rot. – zwol Sep 27 '21 at 13:22
  • @zwol That's an interesting argument. Doesn't that mean you have to disable warnings for "condition is always false" locally inside every file though? Because that one isn't something I'd want to disable project-wide. – Lundin Sep 27 '21 at 13:26
  • But a #define in main header file will visible in all files no? – Aval Sarri Sep 27 '21 at 13:31
  • @zwol Well, I understand your idea but on the other hand, I would expect the test system to compile and test the relevant combination. Catching syntax errors is one thing but the functional part is equally important. – Support Ukraine Sep 27 '21 at 13:35
  • @AvalSarri : thé #define will only be visible in main.c . To have it visible in all files, either you add it in a .h file included in all c files. – Ptit Xav Sep 27 '21 at 13:35
  • @Lundin This was long enough ago that I don't remember whether the compiler, at the time, even _had_ "condition is always false" warnings. – zwol Sep 27 '21 at 13:38
  • @4386427 This was many years ago -- before ubiquitous CI -- and even with CI, it's better if the test build on the developer's local machine catches the mistake. – zwol Sep 27 '21 at 13:39
  • @zwol Apparently current gcc doesn't warn for it even with maximum warnings, which I find strange. Maybe it only checks more complex expressions. I'd expect a compiler warning for this: `for(unsigned char i=255; i>0; i--);` but nope... – Lundin Sep 27 '21 at 13:42
  • @Lundin: `i>0` is not always true. – Eric Postpischil Sep 27 '21 at 14:29
  • @EricPostpischil I meant `i>=0`... but that explains why I didn't get a warning :) Monday and not nearly enough coffee... – Lundin Sep 27 '21 at 14:38
2

if I do #define debug 0 will compiler eliminate/optimize out all the code (that if condition) from final binary?

Yes, if optimizations are enabled. I just tried your code on x86 gcc -O3 and it removed the whole function call with debug set to zero. Basically it just loads the numbers 5, 10 and 15 as parameters to printf then calls it, and that's all the program does. https://godbolt.org/z/b3f17rqe4

An issue here is that the compiler might give you spurious warnings "condition is always false" and similar for if(0). Which is why #ifdef debug ... #endif is a better pattern to use.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    FYI gcc `-O1` should be sufficient to enable dead code elimination (`-fdce`), at least according to the GCC docs. Although it looked like OP's example was doing some dead code elimination even without setting the optimisation level (equivalent to `-O0`). – Ian Abbott Sep 27 '21 at 13:19
  • @IanAbbott Yeah so it seems, though the function inlining doesn't happen at `-O0`. – Lundin Sep 27 '21 at 13:22