Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

What is do { } while(0) in macros and should we use it?

+6
−1

Background

I can see the need to use {} when implementing a function-like macro such as this one:

#define HCF(code) fprintf(stderr, "halt and catch fire"); exit(code);

Because if we use the following calling code

bool bad = false;
if(bad)
  HCF(0xDEADBEEF);
printf("good");

Then it will expand to

bool bad = false;
if(bad)
  fprintf(stderr, "halt and catch fire"); 
exit(0xDEADBEEF);
printf("good");

which was not the intention - it will now exit with an error code even though the program is working as intended.

So the correct way would be to write the macro like this instead:

#define HCF(code) { fprintf(stderr, "halt and catch fire"); exit(code); }

Question

But I've come across macros that instead of just plain braces { } use this:

#define HCF(code) do { fprintf(stderr, "halt and catch fire"); \
                       exit(code); } while(0)

This seems similar to {} but more obscure. What's the purpose of this do { } while(0) and why should it be used instead of { }?

Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comments

2 answers

+10
−0

The sole purpose of the do { } while(0) is to write macros that accommodates to all manner of diverse coding styles. It is quite common not to use braces after if statements, so this is a common coding style:

if(bad)
  HCF(0xDEADBEEF);
else
  printf("good");

If we only used braces as in the first example in the question, it would expand to:

if(bad)
{
  fprintf(stderr, "halt and catch fire"); 
  exit(0xDEADBEEF);
}; // oops
else
  printf("good");

The semicolon written during macro invocation would result in a syntax error "else without previous if" etc. The purpose of do { } while(0) is to swallow up that stray semicolon. Note the lack of semicolon after while(0) which is otherwise the custom in do-while loops:

#define HCF(code) do { fprintf(stderr, "halt and catch fire"); \
                       exit(code); } while(0) 

expands to

if(bad)
  do
  {
    fprintf(stderr, "halt and catch fire"); 
    exit(0xDEADBEEF);
  }while(0);
else
  printf("good");

Which is perfectly valid C. If your purpose was to write a widely portable macro as part of a library or similar, you can probably stop reading here and feel all smug about this neat trick.


However, if your purpose is to write safe C code and only allow safe C code to compile, there is reason to question the purpose of do { } while(0).

Several industry coding standards (MISRA-C, CERT C etc) heavily discourage the style of using control/loop statements without braces {}, since it enables us to write common bugs such as this one:

if(bad)
  fprintf(stderr, "halt and catch fire"); 
  exit(0xDEADBEEF); 

Where the indention fools us to believe that exit is only executed if bad is true. These kind of bugs are particularly common during code maintenance.

One of the most expensive bugs in software history is the infamous "Apple goto fail", which was caused by some version control hiccup. If this code had gone through static analysis before production and the company coding standard enforced {} after each if statement, the bug would have been found.

So there are good reasons to always enforce {} in your coding style. I was once in favour of the if without braces style myself, since it makes the code more compact. However, I have converted to the "always use {} camp" over the years. Other seasoned C programmers I have spoken to have done the same, coming to this conclusion by themselves, rather than having it enforced by a coding standard, after having written numerous missing {} bugs.

So lets assume that we want to use the {} style, always. The do { } while(0) macro style then suddenly turns harmful - because it will allow control/loop statements without braces to compile. Whereas the {} macro style will yield a compiler error because of the stray semicolon - and now we realize that's a good thing.

Why does this post require moderator attention?
You might want to add some details to your flag.

2 comments

Suppose that the Apple coding standard enforced {} after each if. Surely would (a misleadingly indented) goto fail be detected because of this? Or would an unconditional { goto fail; } code recognized as problematical? Incnis Mrsi‭ 12 days ago

@Incnis Mrsi‭ Well it depends on if the braces would surround both gotos or just one. It wouldn't have passed manual code review either. If they had any resemblance of a quality coding standards, then none of the code from that link would be allowed. Not just the brace issue, but goto itself, assignment in conditions and other such signs of code smell. Lundin‭ 12 days ago

+2
−0

Reasons to use the construct

#define FOO(x) do{...} while(0);

(1) as mentioned above, solves the problem of

if (...) FOO(y);

(2) you can to declare variables inside the block, and they harmlessly go out of scope at the end of the block. Without the do{} block, the same symbol would cause a warning (or worse) if it were declared elsewhere in the block in which FOO(x) gets expanded.

Why declare variables inside a macro? In case a macro argument appears more than once in the body, and someone writes FOO(func(y)), where func has side effects. This includes FOO(y++) etc. After the macro expands, the side effect would happen as many times as the macro argument appears in the body!

Declaring a variable inside a do {} block prevents this, as follows:

#define FOO(x) do { long xx = x; func2(xx); func3(xx); } while (0);

Obviously there is still an assumption about type of x, but that is the case anyway if you are going to be calling func2(x) etc

(3) Without the do{} block, there might be ambiguity as to whether FOO(x) expands into a statement or an expression. do{} makes it clearly a statement, which can help catch someone trying to use FOO(x) where an expression is expected. See also: "statement-expressions", aka ({...}), which is a construct in case you want the block to be an expression rather than a statement.

Why does this post require moderator attention?
You might want to add some details to your flag.

2 comments

The question was why to pick do { } while(0) over { }. Your examples work just as fine with { }. Lundin‭ 4 months ago

Fair enough, I missed that. I learned it from looking at the way headers in some system macros were written, and have been doing it ever since. I also got into the habit of using do{} to call attention to there being a block, but this comes from having done a bunch of Perl, where curlies have multiple meanings. One final possible reason: #define FOO(x) {...} If you write (FOO(y)) , it will expand into a statement-expression rather than a statement. That's getting a bit contrived, I admit. Pete W‭ 4 months ago

Sign up to answer this question »