tags:

views:

137

answers:

3

I found this while reading some source code.

 #define MACRO(x)  if((void) 0, (x)); else some_func();

I don't fully understand the reasons behind that operator comma and the void cast. This has probably something to do with macro protection, I know that (void)0 is used sometimes to protect cascading elses in macros such as in if(...) then foo(); else (void)0.

Any ideas of why operator comma is there?

edit: I'm starting to think this has something to do with the owl (0,0).

+2  A: 

The void conversion there is definitely to prevent calling an overloaded operator , since you can't overload with a void parameter. This guarantees that (void)0, has no effect.

Why the comma operator is there? A good question. I really don't know.

ybungalobill
I don't understand. Can you explain in more detail what `((void)0,x)` is supposed to guard against that a simple extra pair of parentheses wouldn't `if((x)); else some_func();` ?
Charles Bailey
@Charles, you're right.
ybungalobill
+1  A: 

This looks a bit as if somebody may have started with some code that included an assert, pre-processed it, and turned the result into a macro. When NDEBUG is defined, assert has to turn into nearly nothing -- but, syntactically, still has to produce some placeholder code. For example, you're allowed to use it in a situation like:

assert(x), *x = 1;

When you compile this with NDEBUG defined, it still needs to compile, but the assert shouldn't do anything. To support that, assert is typically defined something like this:

#undef assert
#ifdef NDEBUG
#define assert(x) ((void)0)
#else
#define assert(x) ((!!x) || __failassert(x, __FILE__, __LINE__))
#endif 

So, if somebody started with code like above, and then looked at the preprocessed version (with NDEBUG defined), they'd see something like:

((void *)0), *x = 1;

...and if they didn't understand the code very well, they might think that ((void)0) really meant/accomplished something.

Jerry Coffin
Good reasoning, but I'm not sure that is the real reason.
Helltone
I'm not *sure* it's the real reason either -- in fact, probably nobody but the original author can do anything but guess, and even he may not remember for sure either...
Jerry Coffin
this "crazy" works with original MACRO : #define CRAZY 0));if((1
@user396672, yes but is that the real reason? AndreyT's explanation sounds at least *halfway* reasonable, but this is working awfully hard to prevent something that it's hard to imagine anybody writing in the first place.
Jerry Coffin
+6  A: 

I would guess that the trick is used to prevent the user form declaring variables in the if condition. As you probably know, in C++ it is legal to do this

if (int i = some_func()) {
   // you can use `i` here
}
else  {
   // and you can use `i` here
}

The use of comma operator in that definition will prevent macro usage like

MACRO(int i = some_func());

and force the user to use only expressions as argument.

AndreyT
You mean `i` instead of `x`, yes?
sje397
That what I though, but to quote Charles, it's true here too: "... what ((void)0,x) is supposed to guard against that a simple extra pair of parentheses wouldn't if((x)); else some_func();".
ybungalobill
@ybungalobill: Yeah, that's right... And extra `()` would solve it in a much simpler way.
AndreyT