1

Say that we have the following for-loop:

#define UPPER 0U
int i;
for(i = 0; i < UPPER; i++) {
    /* foo */
}

This will produce a W549: condition is always true warning, obviously because we get for(i = 0; i < 0; i++) after macro expansion. In the actual code, UPPER is a pre-compile time parameter (i.e., it is set by some build scripts depending on the target platform etc.) that can take any value from 0 to 255 and thus the loop is not just dead code.

How can I elegantly avoid this warning when UPPER == 0?

Obviously, one can wrap the for-loop in an if-statement:

#define UPPER 0U
if(UPPER != 0U) {
    int i;
    for(i = 0; i < UPPER; i++) {
        /* foo */
    }
}

But that's not what I'd call elegant.

phuclv
  • 37,963
  • 15
  • 156
  • 475
mort
  • 12,988
  • 14
  • 52
  • 97
  • 1) did you try to compile your sniplet? `#define` should have no `=` and `;`. 2) in your example the condition is false at first try, so the loop will be skipped completely. – Serge May 17 '16 at 08:53
  • @Serge: No, I just typed it in thinking "what could *possibly* go wrong with this small snipped". For the second point: yes, if `UPPER` is defined as 0. But as I tried to explain in the question, this is a pre-compile parameter, i.e., it may have other values than 0 and thus the for-loop is not dead code. – mort May 17 '16 at 08:56
  • @AjeetShah: To make sure I understand correctly: You are suggesting to introduce a new variable, say `volatile int upper = UPPER;` and use that one in the for loop? – mort May 17 '16 at 08:58
  • A [volatile](https://stackoverflow.com/questions/4437527/why-do-we-use-volatile-keyword-in-c) variable might help. – Ajeet Shah May 17 '16 at 09:04
  • I see warning: `comparison of unsigned expression < 0 is always false [-Wtype-limits]` when using `#define UPPER 0U` but no warning when using `#define UPPER 0`. Is it necessary to use unsigned UPPER? – Ajeet Shah May 17 '16 at 09:57
  • @AjeetShah: No, unsigned is not neccessary – mort May 17 '16 at 09:58

3 Answers3

2

If you don't want to wrap it in code, wrap the code using conditional compilation:

#if UPPER > 0
  int i;
  for(i = 0; i < UPPER; i++) {
      /* foo */
  }
#endif

The elegance stems from:

  • No dead code when UPPER is 0.
  • Completely portable to any C compiler since 1970-01-01
  • Easy to read and understand
Jens
  • 69,818
  • 15
  • 125
  • 179
1

Not a good style of coding, but solves the task. g++ eliminates the dead code even when optimization is off.

#define UPPER 0U
int i;
for(i = 0; &((char*)0)[i] < &((char*)0)[UPPER]; i++) {
    /* foo */
}
Serge
  • 6,088
  • 17
  • 27
  • This adds a dependency on a specific C++ compiler to C code. That's at least as ugly as the code needed to make this work as advertised. – Jens May 17 '16 at 11:32
  • Why? any C compiler should accept this construction. BTW, Also, the commonly used OFFSET macro implemented using the same techniques. – Serge May 17 '16 at 13:44
  • Because you talk of a C++ compiler, not a C compiler, that's why it adds a dependency on C++, according to what the words suggest. If you meant it in another way, it's at least hard to understand. The uglyness of the code is obvious, though. Using address-dereferencing of arrays instead of plain int? Whoa! :-) – Jens May 17 '16 at 19:11
  • I talked about g++ as gcc (I use 4.8.3) does not produce such warning at all, at least I did not succeed to trigger it. – Serge May 17 '16 at 21:29
1

It eliminates warnings of comparison of signed with unsigned and prevents compiler from optimizing the code.

#define UPPER 0U
int i;
volatile int u = UPPER;
for(i=0; i < u; i++){
    /* foo */
}

Tested compilation with gcc -Wall -Wextra myfile.c

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87