C/C++: How to Use the Do-While(0); Construct Without Compiler Warnings Like C4127

C/C++: How to use the do-while(0); construct without compiler warnings like C4127?

Summary: This warning (C4127) in this particular case is a subtle compiler bug. Feel free to disable it.

In depth:

It was meant to catch situations when logical expression evaluates to a constant in non-obvious situations (such as, if(a==a && a!=a), and somehow, it turned while(true) and other useful constructs into invalid.

Microsoft recommends using for(;;) for infinite loop if you want to have this warning on, and there is no solution for your case. This is one of very few Level-4 warnings my company's development conventions allow to disable.

is `warning C4127` (conditional expression is constant) ever helpful?

I don't think it is ever useful. On the contrary, there are more false positives than only the do .. while(0) idiom. Think of constructs like

if(sizeof(long) == 8) { /* ... */ }
if(SOME_CONSTANT_MACRO) { /* ... */ }

The former cannot be replaced by #if directives, the latter could, but some coding style guidelines prefer the if version as syntax checking is still done for the dead code (which isn't dead on other platforms or with other compile-time configuration) and some find it nicer to read.

Warnings (other than those required by the standard, most of which should be treated as errors) are usually emitted for code that is valid but is likely to do something else than what's intended. if(0) or things like this look silly, but don't look as if something other than "syntax check this otherwise dead code" was intended. It may puzzle the reader, but it's unambiguous, and I don't see how this could happen accidentally.

From the examples given thus far (I haven't got MSVC to test on my own), it seems like the warning is for constant expressions in the sense of the C language (that is, not something which can be constant-folded but syntactically isn't a constant expression), so it isn't emitted for if(array), or if(function) (what e.g. gcc -Wall does warn about because it's likely intended to be a function call).

while(0,0) is worse, in my opinion, it triggers a warning with gcc -Wall for a left-hand side of a comma operator without side-effects, a warning I can imagine to be occasionally useful (and which usually is easy to avoid). This warning disappears with while((void)0,0).

I suggest turning the warning off.

In C macros, should one prefer do { ... } while(0,0) over do { ... } while(0)?

Well, I'll go for an answer:

Is there a legitimate reason why one should prefer the second form of the macro... ?

No. There is no legitimate reason. Both always evaluate to false, and any decent compiler will probably turn the second one into the first in the assembly anyway. If there was any reason for it to be invalid in some cases, C's been around far long enough for that reason to be discovered by greater gurus than I.

If you like your code making owl-y eyes at you, use while(0,0). Otherwise, use what the rest of the C programming world uses and tell your customer's static analysis tool to shove it.

C4127: Conditional Expression is Constant

It looks like you know what is going on, and you are fine with this.

Compiler pragmas are meant for cases like that:

__pragma(warning(push))
__pragma(warning(disable:4127))
if (sizeof(alias_wchar_t) == sizeof(wchar_t)) {
__pragma(warning(pop))
}

Essentially, you are telling the compiler (and even more importantly, to human readers of your code) that you have reviewed the warning, and that you know what you are doing.

why to write C code like while((void)0, 0)

At a guess, it's probably to shut up a compiler warning like "condition is constant".

Since (what C classifies as) a constant expression can't include a comma operator, using one can convince some compilers that an expression isn't a constant (even in a case like this, where it really is).

Is there a gcc warning for conditional expression is constant?

I do not see a warning that corresponds to MSDN C4127. GCC does have a warning that is somewhat similar in intent, but not to address your problem: -Wtype-limits

Warn if a comparison is always true or always false due to the
limited range of the data type, but do not warn for constant
expressions. For example, warn if an unsigned variable is compared
against zero with < or >=. This warning is also enabled by
-Wextra.

As you can see, GCC explicitly states it does not warn about constant expressions. The motivation for this may be due to the common use of constant expressions to leverage the compiler's dead code elimination so that macros (or portions of it) can be optimized away by using a compile time constant. It would be used as an alternative to conditional compilation (#if defined() and #if X == Y), as the macro reads more naturally like a regular function. As a hypothetical example:

#define VERIFY(E) \
do { \
if (NO_VERIFY) break; \
if (!(E) && (VERIFY_LOG_LEVEL >= log_level() || VERIFY_LOG_ALWAYS)) { \
log("validation error for: " #E); \
} \
} while (0)


Related Topics



Leave a reply



Submit