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.
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.
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.
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; }