5

Possible Duplicate:
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?

When one needs to execute multiple statements within preprocessor macro, it's usually written like

#define X(a) do { f1(a); f2(a); } while(0)

so when this macro is used inside expressions like:

if (...)
    X(a);

it would not be messed up.

The question is: wherever I've seen such expression, it's always do { ... } while(0);. Is there any reason to prefer such notion over (in my opinion more clear one) if (1) { ... }? Or am I wrong in my observations and they are equally popular?

Community
  • 1
  • 1
aland
  • 4,829
  • 2
  • 24
  • 42
  • 3
    `#define ever (;;)` then `for ever { ... }` – Vinicius Kamakura May 23 '12 at 13:02
  • 3
    @KingsIndian the Q you linked to asked *why* such statements exist at all. aland here wants to know why one is preferable to the other, I think that's a perfectly valid, and also different question. – penelope May 23 '12 at 13:13
  • 1
    @penelope Moreover if I say dup, then it's not going to become dup right away. `At least 4 other people have to agree with me` and also it can be re-opened if community thinks all 5 close-voters got it wrong. – P.P May 23 '12 at 13:23

5 Answers5

9

Nope, you're not wrong.

There's actually a nice reason:

#define my_code if (1) { ... }

if (1)
    my_code;

The problem is with the ; ! It shouldn't be there... and that would just look strange and not in the spirit of the language. You can either choose to have a code that expands in to two ; in a row, or a code that looks un-c-ish :)

On the other hand, the do-while construction does not have that problem.


Also, as others mentioned, there's an else problem:

if (1)
    my_code;
else { ... }

Ignoring the ; issuse, the else block now belongs to the wrong if.

penelope
  • 8,251
  • 8
  • 45
  • 87
7

if can be as safe as do/while only if there is else branch. E.g.:

#define X(a) if(1) { f1(a); f2(a); } else{}

Is as safe as:

#define X(a) do { f1(a); f2(a); } while(0)

So that the user can't do:

X(...) else ...;

One difference is that when using do/while it requires a ; at the end, whereas if/else doesn't.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    your solution still has the `;` issue - you could use it in code as `if (condition) X(a)` without `;`, it would not force the user to end his statements, producing wired un-semicolon-ed code – penelope May 23 '12 at 13:12
  • I'd say `if{}else{}` is more universal because it can be used with or without `;`. Personally, I don't like macros looking like plain code, so I prefer no `;` after a macro. – Maxim Egorushkin May 23 '12 at 13:24
  • I'm accepting penelope's answer since it covers both differences between two cases in question. No offence meant. – aland May 23 '12 at 13:37
  • No worries, it's your question. – Maxim Egorushkin May 23 '12 at 13:40
  • I don't think `if (x) X(a); else doSomethingElse();` will work if `X(a)` uses the `if(1){..}else{}` form, but it will work just fine with the `do{...}while(0)` form. – supercat Aug 13 '14 at 17:38
5

Consider this:

if(foo)
    X(a);
else
    whatever();

This would expand to:

if(foo)
    if(1) { ... }
else
    whatever();

Which is bad because now the else belongs to the wrong if.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
2

Using do... while allows you to break out if necessary.

James
  • 9,064
  • 3
  • 31
  • 49
  • break out of what? he wants to use/not use `do-while` as a *macro* – penelope May 23 '12 at 13:08
  • 4
    To break out the body of the macro early if necessary. It's used all over the place in the linux source codes. – James May 23 '12 at 13:11
  • To me, just a half-scentence explanation looks a bit confusing and unocnvincing. Could you add a code snippet that demonstrates your point? – penelope May 23 '12 at 13:15
2

When you use #define X(a) do { ... } while(0) form, it forces you to put ; at the end of the statement X(1).

Alex Bakulin
  • 1,668
  • 11
  • 17