9

It's common practice in C to use:

#define FOO() do { /* body */ } while (0)

While this is fine, it's also possible to do:

#define FOO() { /* body */ }((void)0)

{...}((void)0) has many of the same benefits: you can't accidentally merge logic, and a ; is required at the end of the line, so odd expressions like this don't go by un-noticed: FOO() else {...}.

The only difference I've noticed is it means you need to use braces in if-statements.

if (a)
    FOO();
else
    BAR();

Must be written as:

if (a) {
    FOO();
} else {
    BAR();
}

Other then this quirk, it seems to work well, preventing the same kinds of problems do/while method is typically used for.

Are there any significant differences between the 2 methods?

Said differently, if you see a code-base using {...}((void)0), are practical reasons to switch to using do{..}while(0), besides the one difference already noted?

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 4
    The `{ … } (void)0` variant is never used in practice — I've never seen it suggested before, even. It is plain _weird_! And pointless. And useless, because you can't use it as simply as the `do { … } while (0)` alternative. The `(void)0` cast buys you precisely nothing of value — it is devoid of benefit. – Jonathan Leffler Feb 28 '15 at 03:11
  • 6
    Practical difference #1: people know and recognize the `do { ... } while(0)` variant, and not the other. – Jerry Coffin Feb 28 '15 at 03:13
  • 5
    The difference you pointed out is huge. – R Sahu Feb 28 '15 at 03:17
  • @xxbbcc, `{ ... }(void)0` and `if (1) { ... } else` are completely different. – ideasman42 Feb 28 '15 at 03:28
  • @ideasman42: You're right. It will produce an error message. I take it back. But it still strikes me as a bad idea. – rici Feb 28 '15 at 03:28
  • I agree, `(void)0` does not force a semicolon next. – Ben Voigt Feb 28 '15 at 03:53
  • @Ben Voigt , `(void)0` does force a semicolon next (with clang and gcc at least) – ideasman42 Feb 28 '15 at 04:23
  • 1
    @ideasman42: No, the grammar does not require a semicolon next. See http://rextester.com/KJLA9675 – Ben Voigt Feb 28 '15 at 04:26
  • Can you show an example of `{}(void)0` used without a terminating semicolon? (`void func() { (void)0 }` -> `error: expected ';' before '}' token`) – ideasman42 Feb 28 '15 at 04:27
  • I linked an example right there in my comment. It would have been an answer, but the question got closed, so I edited the comment. – Ben Voigt Feb 28 '15 at 04:29
  • @Ben Voigt, excellent point, would be a good answer to the question in-fact. – ideasman42 Feb 28 '15 at 04:35
  • @Ben Voigt, the example you linked uses C++, I managed to use the comma operator `void func() { FOO(), call(); }` which is disallowed if `while(0)` is used. But this is not so different from C regular syntax, where you can do 2 statements too `func(), func();` – ideasman42 Feb 28 '15 at 04:54
  • 1
    Same example works fine in C: http://rextester.com/ADOSK79081 – Ben Voigt Feb 28 '15 at 05:04
  • @Ben Voigt, in this case `{ ... } ((void)0)` solves the problem. updated the question. – ideasman42 Feb 28 '15 at 10:27
  • @JonathanLeffler do...while(0) is weird too, it's just that we are used to this weird :) – M.M Feb 28 '15 at 23:37

2 Answers2

7

The practical difference is exactly what you pointed out.

The do { ... } while (0) idiom means that the macro can be used in any context that requires a statement.

Your suggested idiom { ... } ((void)0) can be used safely in most contexts that require an expression -- but it can fail if it's used in an unbraced if statement.

I can think of no good reason to use an unfamiliar idiom that almost always works, when there's a well known idiom that always works.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 2
    Theres one case it doesn't work - when you want to use a `break` within the macro, (admittedly not something which is done often though). – ideasman42 Mar 18 '15 at 05:55
2

One difference is you can use break with #define FOO() do { /* body */ } while (0) but not with #define FOO() { /* body */ }(void)0.

Let's say you are inside a function, say hello(), and doing something in #define FOO() do { /*some device operation */ } while (0) but some error occurred so you no longer want to proceed with that device but there are other statements in function hello() you want to execute, let's say for another device.

So if you use second statement then you will do return most probably which will exit out of hello() but if you use the first statement you can happily break and do some operation in same function hello() for another device.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user1627167
  • 339
  • 1
  • 8
  • 2
    I'm not convinced that's a compelling difference. You can code the body so that instead of `if (condition) break; …rest of body…` you write `if (!condition) { …rest of body… }`. That's an essentially trivial change. You could even embed a `do ... while (0)` inside the `{ …here… } (void)0` version. – Jonathan Leffler Feb 28 '15 at 03:54
  • Posting an example :) – user1627167 Feb 28 '15 at 03:57
  • 1
    @JonathanLeffler how about multiple if condition ? though you can always code but will be readable ? like this http://ideone.com/wfC6Ib – user1627167 Feb 28 '15 at 04:15
  • 1
    ok see this link if it convince you. but one reason for choosing one over the other is that. It makes things much more simpler to read and write – user1627167 Feb 28 '15 at 04:22
  • Which link? And are you actually posting an example, or am I misinterpreting what your comment meant. – Jonathan Leffler Feb 28 '15 at 04:23
  • that's the example in link that I have written because of limitation of words in comment – user1627167 Feb 28 '15 at 04:24
  • Oh, you mean the link http://ideone.com/wfC6Ib in a previous comment? Sorry; didn't notice that. I think it means you added the link after I saw the comment and responded. I'd need to see what the macros `communicate` and `call` expand to, since they don't leave valid code when they are written as shown on ideone. But there's no visible reason to be using the `FOO` macro; it has no parameters, so it could be a (possibly `inline`) function instead, which would be a lot cleaner and clearer. Put succinctly, that example does not change my mind. – Jonathan Leffler Feb 28 '15 at 04:26
  • One of the reasons I was considering `{...}((void)0)` is precisely because its not allowing for `break` statements. – ideasman42 Mar 01 '15 at 00:26