filberol
filberol

Reputation: 11

do { } while(0) alternative in macro definition or any other possible options

I have encountered a way of making a multiline macro function definition in C/C++ compilation, that does not meet any clear code conventions (and possibly creates performance drawbacks?). Is it the only way to achieve the goal of making macro functions? Are developers going to introduce any other ways to do it?

I see that is not the first question about while(0), but I'm looking for any possible alternatives, maybe I should just write normal functions.

I can see that that this technique is used in the Linux kernel, thus may I say that it's legal to write like that? Linux repository search

Upvotes: 0

Views: 224

Answers (2)

Aconcagua
Aconcagua

Reputation: 25536

At very first: Macros typically are harder to read and often make debugging more complicated – if applicable, functions or other alternatives, if the concrete use case allows, should be preferred.

If macros cannot be avoided for whatever reason, then actually it would work to simply wrap multiple expressions within a pair of braces. The do { } while(0) approach, though, enforces placing a semicolon afterwards, which is desirable to produce clean code (usage of the macro looks like a function call or other kind of single expression) and prevents usage of outside of functions (though the macros wrapped code usually would do so as well). So just wrapping into braces is clearly inferior to the do { } while(0) approach.

Actually there appears to be yet another alternative:

#define FOO if(1) { /* multiple expressions */ } else ((void)0)

Chris Kline highlights in a comment to this answer to a similar question the superiority of over the do { } while(0) approach in respect of safety in the case of the macro argument themselves containing (complex) code. However writing macros in such kind can be considered dirty code and should not ever be applied; in contrast this variant silently discards subsequent expressions e.g. if appended via the sequence (comma) operator like:

FOO, bar();
//   ^ unexpectedly won't get called!

so doesn't guarantee safe usage!

Upvotes: 1

klutt
klutt

Reputation: 31409

Macros and clear code don't mix well in the first place. That's basically just the way it is.

And yes, do ... while(0) is a bit of a clunky workaround. However, it has become a defacto standard of how to do what you want to do. If you find some other clever alternative, you will likely make the code less clear, because C programmers recognize the do ... while(0) as the established convention.

Don't worry about performance. Any compiler can see that do ... while(0) will be executed only once and will optimize the loop away.

According to this answer it's the only way to do what you want to do. I don't know if it's technically true, but I'm pretty sure there are no good ways around it. At least not for all situations. In some situations it can work to use the comma operator, like #define FOO(x) a(x), b(x) but that will not work for more complicated situations. However, there are also situations where you will have to use that approach. For instance, if you use if(FOO(x)) the do-while will give an error, but the neither comma nor do-while does not work for a = FOO(x). You can make it work with #define FOO(x) (a(x), b(x)), but you will still be limited to very simple constructs.

I try to stay away from macros whenever possible. They tend to make debugging much harder.

Upvotes: 2

Related Questions