views:

606

answers:

7

I'm often use do-while(0) construct in my #defines, for the reasons described in this answer. Also I'm trying to use as high as possible warning level from compiler to catch more potential problem and make my code more robust and cross-platform. So I'm typically using -Wall with gcc and /Wall with MSVC.

Unfortunately MSVC complain about do-while(0) construct:

foo.c(36) : warning C4127: conditional expression is constant

What should I do about this warning?

Just disable it globally for all files? It does not seems to be good idea for me.

+1  A: 

This "while(0)" stuff is a hack and has just turned around to bite you.

Does your compiler offer #pragmas for selectively and locally turning off specific error messages? If so, that might be a sensible alternative.

Carl Smotricz
Yes, MSVC supports pragmas, but how can I wrap macros itself in that pragma?
bialix
Sorry, don't know. This was an idea, a hint from me and I hoped it would inspire a solution. I don't remember dealing with this kind of problem before.
Carl Smotricz
C99 describes _Pragma() as an alternative to the pre-processor form #pragma precisely so it can be generated as part of a macro. Microsoft has declared that they're not interested in implementing C99, but I don't know if this feature is already there (given their front-end vendor).
Novelocrat
MSVC has the `__pragma()` preprocessor operator, which unfortunately is slightly different from C99's `_Pragma()` operator (C99's take a string literal, MSVC's takes tokens that aren't in a string): http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
Michael Burr
A: 

I must say, I've never bothered with the do..while construct in macros. All code in my macros is itself included in braces, but without the do-..while. For example:

#define F(x) \
    {   \
     x++; \
    }   \

int main() {
    int a = 1;
    F(a);
    printf( "%d\n", a );
}

Also, my own coding standard (and informal practice for years) has been to make all blocks, wherever they occur be enclosed in braces, which also more or less removes the problem.

anon
do-while(0) is wide used construct AFAIK.
bialix
I know. I'm suggesting it is not necessary.
anon
+1 It may be "widely" used (I've never seen it in production code, anyway) but I don't think it is necessary. After all macros should be avoided in the first place, so if you put them in, keep them simple. Don't introduce "loops" in my code.
Daniel Daranas
Yeah, it is widely used, but it's only really necessary in a few border cases that I tend to avoid anyway. In sane code, regular braces as shown here will usually suffice
jalf
I sometimes forget semicolons, and it makes the code horrible to read :/
Johannes Schaub - litb
@litb Who are you talking to? If me, you can either use or omit the semicolon. And which bit of the code looks "horrible"?
anon
-1 Fails with: if (a==b) F(bar); else someFunc();
Tomas
@Tomas See my second paragraph.
anon
@Neil your coding habit cannot be applied to everybody. so I think your answer is not a good guide. and some lines with trailing semi-colon and some lines without it is horrible.
sevity
+11  A: 

Summary: This warning (C4127) is a 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.

Pavel Radzivilovsky
I know about for(;;) but there it's not applicable as you said. I tend to follow your advice, just waiting for some other suggestions.
bialix
to me, for(;;) just looks ugly.
Pavel Radzivilovsky
A: 

You can use #pragma warning to:

  1. save the state
  2. disable the warning
  3. write the offending code
  4. return the warning to their previous state

(you need a # before the pragmas, but SO is having a hard time dealing with them and formatting at the same time)

pragma warning( push )
pragma warning( disable : 4127)
// Some code
pragma warning( pop )

You want to push/pop the warnings rather then disable/enable because you do not want to interfere with the command line arguments that might be chosen to turn warnings on/off (someone may use the command line to turn off the warning, you do not want to force it back on... the code above deals with that).

This is better than turning the warning off globally since you can control it just for the part you want. Also you can make it part of the macro.

TofuBeer
I'm not sure how can I makew it part of the macro. If I put pragmas just after `#define foo(x) \ ` I've got error: error C2162: expected macro formal parameter
bialix
I don't have an MS compiler handy... so cannot test that. I guess wrap the macro usage in that code if you cannot put it in the macro. You are sure you did it as #pragma? (just checking :-)
TofuBeer
You can't put pragmas in the macro, so you'd have to disable the warning everywhere you __use__ the macro. Nasty.
Graeme Perrow
Reason not to code like that :-)
TofuBeer
A: 

#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)?

#define STUFF for (;;) {f(); g(); break;}?

ephemient
won't work for plain ANSI C 89
bialix
I hardly expect anybody using MSVC to be compiling plain C.
ephemient
OK, so I'm that crazy guy then.BTW, C extensions for Python usually compiled with MSVC on Windows.
bialix
+1  A: 

Perhaps your code needs more owls:

do { stuff() } while (0,0)
Eric Seppanen
for bonus points add // orly?
jk
Interesting, but actually does not help. It produces another warning :-)warning C4548: expression before comma has no effect; expected expression with side-effect
bialix
A: 

There is a solution but it will add more cycles to your code. Don't use explicit value in the while condition.

You can make it like this:

file1.h

extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) \
do \
{ \
} \
while(I_am_a_zero);

the variable I_am_a_zero should be defined in some .c file.

Anyway this warning doesn't show up in GCC :)

See this related question.

Yousf
Is not this const variable will prevent for optimization of the loop and will introduce unneeded check for zero?
bialix
Yes, that's why Yousf said it will add more cycles to your code.
jamesdlin
no, the compiler will not know that variable "I_am_a_zero" is actually a zero while compiling; Because it is an extern symbol which will be fulfilled in linking stage.
Yousf