tags:

views:

262

answers:

4
+11  A: 

The do while is a common convention which makes the macro require a trailing semi colon like a standard c function would. Other than that it just ensures the variable that has been freed is set to NULL so that any future calls to free it will not cause errors.

Nick
Wow, now that you explain it that way, it makes perfect sense.
Daniel A. White
Excellent. I've seen the `do {} while(0)` bit before but never understood why.
Brandon Bodnár
It not only makes sense, but if you have a really good compiler, it should optimize the loop out. I don't know if any like MSVC, gcc, icc, lcc, etc. remove the loop like they ought to, but optimization is surely a difficult problem to solve when it comes to compiling code. :P
Dustin
The main point about do/while(0) is to avoid expanded code that is very different the programmer's intention.
janm
@janm That can be accomplished by just using braces without needing the useless looking do/while(0). For example `#define SAFE_FREE(x) { if ((x) != NULL) {free(x); x=NULL;} }`
Brandon Bodnár
@Brandon Bodnár: No. Consider "if (test) SAFE_FREE(x); else blah();" Instant syntax error.
janm
@janm: Good point.
Brandon Bodnár
+12  A: 
do { stuff() } while(0);

is doing the exact same thing as stuff(). So what's the big deal, then? The issue is with the syntax of macros. Suppose we defined the macro like:

#define SAFE_FREE(x) if ((x) != NULL) { free(x); x=NULL; }

Then, there are two issue. The first is relatively minor: uses of SAFE_FREE no longer require a trailing semi-colon. More importantly, though, code like:

if (...)
  SAFE_FREE(x)
else
   stuff();

Will expand to:

if (...)
  if ((x) != NULL) {
    free(x);
    x = NULL;
  } else
    stuff();

Defining the macro as above prevents weird behavior as above, since do { ... } while(0) acts just like a statement without its semicolon.

jon
W.r.t "I don't know if any like MSVC, gcc, icc, lcc, etc. remove the loop like they ought to, but optimization is surely a difficult problem to solve when it comes to compiling code."You don't even need a particularly good compiler. It's such a common construct that GCC optimizes it out even with optimizations turned off. It's not even an optimization-- something to make the code run faster-- per se: just a trivial elimination of unnecessary syntax.
jon
@jon: gcc does not optimize this out with optimizations turned off. gcc doesn't do anything that restructures your code when optimizations are turned off, otherwise debugging would be a nightmare.
Jason Coco
@Jason Coo: um... yes it does. Verified a simple example both with and without the "do { ...} while(0);" wrapper, with -O0 and the default options. gcc gives me the exact same output. (4.3.2, Debian 4.3.2-1.1, on Debian lenny.)
jon
Why not use just a block? It seems the do while(0) is still redundant and could be accomplished with a set of curly braces as shown in the above code. The semicolon is the only reason for the while that I can see.
Billy ONeal
@Jason how would debugging become a nightmare?
Johannes Schaub - litb
A: 

The idea behind the do/while(0) is that you can use the macro where you would use a function call without unexpected errors.

For example, if you had code like:

if (today_is_tuesday())
    SAFE_FREE(x);
else
    eat_lunch();

and the macro was just:

#define SAFE_FREE(x)  if (x) { free(x); x = 0; }

You would get a very different result. The do/while convention avoids those errors by making it behave consistently.

janm
+2  A: 

BTW On the C++ Style and Technique FAQ Bjarne Stroustrup suggests using an inline (template) function to do a "delete and null"

template<class T> inline void destroy(T*& p) { delete p; p = 0; } 
hamishmcn