Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

do{..}while(0) macro substitutions

1,482 views
Skip to first unread message

Yan

unread,
Dec 30, 2004, 6:29:27 PM12/30/04
to
A lot of times when reading open software, i come across macros that are
defined as follows:

#define CALL_FUNCS(x) \
do { \
func1(x); \
func2(x); \
func3(x); \
} while (0);

now, of course this will work but how is this any better than:

#define CALL_FUNCS(x) \
{ \
func1(x); \
func2(x); \
func3(x); \
}

i can't see how the compiler can optimize (a) any better than (b) or in
any case can (b) break what (a) won't. Any input will be appreciated.

tia

Alexandre

unread,
Dec 30, 2004, 6:46:19 PM12/30/04
to
Hello,

Yan a écrit :


> A lot of times when reading open software, i come across macros that are
> defined as follows:
>
> #define CALL_FUNCS(x) \
> do { \
> func1(x); \
> func2(x); \
> func3(x); \
> } while (0);

are you sure there is ";" at the end ?
because I thought the reason why you use "do { } while(0)" is this ";" !
you don't have to put it there, and I explain why after...

>
> now, of course this will work but how is this any better than:
>
> #define CALL_FUNCS(x) \
> { \
> func1(x); \
> func2(x); \
> func3(x); \
> }
>
> i can't see how the compiler can optimize (a) any better than (b) or in
> any case can (b) break what (a) won't. Any input will be appreciated.

you should see where it's used in the code, and then you will understand !
in the code you will find this :

...
CALL_FUNCS(12); /* becareful of this ";" */
...

so the preprocessor will replace CALL_FUNCS(12) by :
(a)
...
do { \
func1(x); \
func2(x); \
func3(x); \
} while (0); /* <- this ";" will end do { } while(0) in good way */
...

(b)
...
{ \
func1(12); \
func2(12); \
func3(12); \
}; /* <- too much ";" */
...

Maybe there is another reason, but I'm sure I read this explanation
somewhere (maybe here).

Alexandre
--
"That's what they should teach us here", he (Harry Potter) thought, ...,
"how's girls' brains work ... it'd be more useful than Divination, anyway
..."

Harry Potter and the Order of the Phoenix
J.K. Rowling

Ben Pfaff

unread,
Dec 30, 2004, 6:43:07 PM12/30/04
to
Yan <rot...@gmail.com> writes:

> A lot of times when reading open software, i come across macros that
> are defined as follows:
>
> #define CALL_FUNCS(x) \
> do { \
> func1(x); \
> func2(x); \
> func3(x); \
> } while (0);

Read the FAQ.
--
Ben Pfaff
email: b...@cs.stanford.edu
web: http://benpfaff.org

Andrey Tarasevich

unread,
Dec 30, 2004, 6:51:08 PM12/30/04
to

It is not about optimization.

The whole idea of using 'do/while' version is to make a macro which will
expand into a regular statement, not into a compound statement. This is
done in order to make the use of function-style macros uniform with the
use of ordinary functions in all contexts.

Consider the following code sketch

if (<condition>)
foo(a);
else
bar(a);

where 'foo' and 'bar' are ordinary functions. Now imagine that you'd
like to replace function 'foo' with a macro of the above nature

if (<condition>)
CALL_FUNCS(a);
else
bar(a);

Now, if your macro is defined in accordance with the second approach
(just '{' and '}') the code will no longer compile, because the 'true'
branch of 'i' is now represented by a compound statement. And when you
put a ';' after this compound statement, you finished the whole 'if'
statement, thus orphaning the 'else' branch (hence the compilation error).

One way to correct this problem is to remember not to put ';' after
macro "invocations"

if (<condition>)
CALL_FUNCS(a)
else
bar(a);

This will compile and work as expected, but this is not uniform. The
more elegant solution is to make sure that macro expand into a regular
statement, not into a compound one. One way to achieve that is to define
the macro as follows

#define CALL_FUNCS(x) \
do { \
func1(x); \
func2(x); \
func3(x); \
} while (0)

Now this code

if (<condition>)
CALL_FUNCS(a);
else
bar(a);

will compile without any problems.

However, note the small but important difference between my definition
of 'CALL_FUNCS' and the first version in your message. I didn't put a
';' after '} while (0)'. Putting a ';' at the end of that definition
would immediately defeat the entire point of using 'do/while' and make
that macro pretty much equivalent to the compound-statement version.

I don't know why the author of the code you quoted in your original
message put this ';' after 'while (0)'. In this form both variants are
equivalent. The whole idea behind using 'do/while' version is not to
include this final ';' into the macro (for the reasons that I explained
above).

--
Best regards,
Andrey Tarasevich

E. Robert Tisdale

unread,
Dec 30, 2004, 6:54:47 PM12/30/04
to
Ben Pfaff wrote:

> Yan writes:
>
>>A lot of times when reading open software,

>>I come across macros that are defined as follows:


>>
>>#define CALL_FUNCS(x) \
>>do { \
>> func1(x); \
>> func2(x); \
>> func3(x); \
>>} while (0);
>
> Read the FAQ.

Could you please cite and quote the FAQ
that is relevant to this question?

italy

unread,
Dec 30, 2004, 7:15:44 PM12/30/04
to
It seems like this is an annoyance, so I wouldn't use any approach
mentioned above. If you really feel the conceit to do this, then
perhaps a function would be a better approach, even though it may
create overhead in some cases.
Good question.

-Adam Roan
"Just plain neat."

Dan P.

unread,
Dec 30, 2004, 7:23:46 PM12/30/04
to

"E. Robert Tisdale" <E.Robert...@jpl.nasa.gov> wrote in message
news:cr24cs$hto$1...@nntp1.jpl.nasa.gov...


I used Google

http://www.google.com/

to search for

"comp.lang.c faq multi-statement"

and the 1st link showed the FAQ # to be 10.4

http://www.eskimo.com/~scs/C-faq/q10.4.html

E. Robert Tisdale

unread,
Dec 30, 2004, 7:30:57 PM12/30/04
to
Yan wrote:

> A lot of times when reading open software,

> I come across macros that are defined as follows:


>
> #define CALL_FUNCS(x) \
> do { \
> func1(x); \
> func2(x); \
> func3(x); \
> } while (0);

This practice is obsolete and should be discouraged.
Write inline function definitions instead:

inline static
void CALL_FUNCS(double x) {
func1(x);
func2(x);
func3(x);
}

Flash Gordon

unread,
Dec 30, 2004, 8:12:23 PM12/30/04
to

Try things like:

if (cond)
CALL_FUNCS(a);
else
CALL_FUNCS(b);

and see how far you get.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.

Keith Thompson

unread,
Dec 30, 2004, 9:03:49 PM12/30/04
to
"italy" <ita...@gmail.com> writes:
> It seems like this is an annoyance, so I wouldn't use any approach
> mentioned above. If you really feel the conceit to do this, then
> perhaps a function would be a better approach, even though it may
> create overhead in some cases.

It's a common C idiom that all C programmers should be familiar with.
If you find it annoying -- well, it's not the worst annoyance in the
language.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Keith Thompson

unread,
Dec 30, 2004, 9:55:45 PM12/30/04
to

That's great if you happen to have a compiler that supports inline
function definitions *and* you're not concerned about your code being
ported to a compiler that doesn't. You might have that luxury. Don't
assume that everyone else does.

Mysidia

unread,
Dec 30, 2004, 10:32:31 PM12/30/04
to
> This practice is obsolete and should be discouraged.
> Write inline function definitions instead:

I strongly disagree. There are certainly many cases where
the approach is best.

Consider this example

#define CALL_FUNC(x, y, z) \
do { \
x##_fun1(y, #z); \
x##_fun2(y, #z); \
x##_fun3(y, #z); \
} while(0)

Now let how do you propose an inline function can handle
this common sort of construct?

By all counts, inline functions don't quite cut it for this situation.

An inline function has to assume a specific datatype for all use
of the macro, which somewhat restricts the input, and somewhat
defeats major advantages of using macros.

like
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Is more general than

double max(double a, double b) { return a > b ? a : b; }

The latter treats everything as a double.
i.e. if you called max() on two ints... you get totally unnecessary
conversions from int to double

E. Robert Tisdale

unread,
Dec 30, 2004, 10:06:40 PM12/30/04
to
Keith Thompson wrote:

> That's great if you happen to have a compiler
> that supports inline function definitions
> *and* you're not concerned about your code being ported to a compiler that doesn't.
> You might have that luxury. Don't assume that everyone else does.

I cordially invite and welcome all comp.lang.c subscribers
to come on into the twenty first century.

Flash Gordon

unread,
Dec 31, 2004, 3:49:44 AM12/31/04
to

http://www.eskimo.com/~scs/C-faq/q10.4.html

Now why don't *you* read the FAQ.

Oh yes, I remember now, you are a troll, that's why you don't read the FAQ.

Emmanuel Delahaye

unread,
Dec 31, 2004, 4:32:08 AM12/31/04
to
Yan wrote on 31/12/04 :

> #define CALL_FUNCS(x) \
> do { \
> func1(x); \
> func2(x); \
> func3(x); \
> } while (0);

This is certainely not what you have seen. Read again, it is more
likely:

} while (0)

and it's precisely the point.

> #define CALL_FUNCS(x) \
> { \
> func1(x); \
> func2(x); \
> func3(x); \
> }
>
> i can't see how the compiler can optimize (a) any better than (b) or in any
> case can (b) break what (a) won't. Any input will be appreciated.

It's not a question of optimization, but it's the only non invasive
known trick that forces the user to put a ';' after the macro usage,
making the syntax consistent.

Nothing else.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"

Emmanuel Delahaye

unread,
Dec 31, 2004, 4:37:29 AM12/31/04
to
E. Robert Tisdale wrote on 31/12/04 :

Your are correct in theory, but the C-compilers installed on zillions
of machines across the world and not magically going to switch to C99
just because a new release of the language came out...

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.

Raymond Martineau

unread,
Dec 31, 2004, 11:13:57 AM12/31/04
to
On 30 Dec 2004 19:32:31 -0800, "Mysidia" <mys...@gmail.com> wrote:

>An inline function has to assume a specific datatype for all use
>of the macro, which somewhat restricts the input, and somewhat
>defeats major advantages of using macros.
>
>like
>#define MAX(a, b) ((a) > (b) ? (a) : (b))
>Is more general than
>
>double max(double a, double b) { return a > b ? a : b; }
>
>The latter treats everything as a double.
>i.e. if you called max() on two ints... you get totally unnecessary
>conversions from int to double

If you use the macro MAX(a++, b), you'd invoke fairly undefined behaviour
with one of the expressions being evaluated twice.


Emmanuel Delahaye

unread,
Dec 31, 2004, 1:34:45 PM12/31/04
to
Raymond Martineau wrote on 31/12/04 :

> If you use the macro MAX(a++, b), you'd invoke fairly undefined behaviour
> with one of the expressions being evaluated twice.

A C-programmer fitted with a working brain won't write that.

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++

Stephen Sprunk

unread,
Dec 31, 2004, 3:32:58 PM12/31/04
to
"Emmanuel Delahaye" <em...@YOURBRAnoos.fr> wrote in message
news:mn.fa7d7d4cc...@YOURBRAnoos.fr...

> Your are correct in theory, but the C-compilers installed on zillions
> of machines across the world and not magically going to switch to C99
> just because a new release of the language came out...

By that argument we should all still be writing in K&R C instead of C89; one
must draw a line somewhere, and it's perfectly valid in many cases to make
it C99 (or C89 with very common extensions).

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Keith Thompson

unread,
Dec 31, 2004, 4:04:50 PM12/31/04
to
"Stephen Sprunk" <ste...@sprunk.org> writes:
> "Emmanuel Delahaye" <em...@YOURBRAnoos.fr> wrote in message
> news:mn.fa7d7d4cc...@YOURBRAnoos.fr...
>> Your are correct in theory, but the C-compilers installed on zillions
>> of machines across the world and not magically going to switch to C99
>> just because a new release of the language came out...
>
> By that argument we should all still be writing in K&R C instead of C89; one
> must draw a line somewhere, and it's perfectly valid in many cases to make
> it C99 (or C89 with very common extensions).

As far as I know, there are very few platforms with an available K&R C
compiler but no available C89/C90 compiler. I understand that Recent
releases of gcc, for example, assume that the hosting compiler is C90
compliant.

On the other hand, there are still plenty of platforms with no
available C99 compiler. I'd be very pleasantly surprised to discover
that that's not the case.

E. Robert Tisdale

unread,
Dec 31, 2004, 4:15:27 PM12/31/04
to
Keith Thompson wrote:

> There are still plenty of platforms with no available C99 compiler.

Can you enumerate them?

The GNU C compiler ports almost everywhere
and is pretty near C99 compliant.

Mathew Hendry

unread,
Dec 31, 2004, 6:00:24 PM12/31/04
to
On Fri, 31 Dec 2004 11:13:57 -0500, bk...@ncf.ca (Raymond Martineau) wrote:

>On 30 Dec 2004 19:32:31 -0800, "Mysidia" <mys...@gmail.com> wrote:
>
>>#define MAX(a, b) ((a) > (b) ? (a) : (b))
>

>If you use the macro MAX(a++, b), you'd invoke fairly undefined behaviour

As opposed to unfairly defined? :)

>with one of the expressions being evaluated twice.

There's a sequence point between the two.

-- Mat.

Keith Thompson

unread,
Dec 31, 2004, 10:09:45 PM12/31/04
to
"E. Robert Tisdale" <E.Robert...@jpl.nasa.gov> writes:
> Keith Thompson wrote:
>
>> There are still plenty of platforms with no available C99 compiler.
>
> Can you enumerate them?

Nope.

> The GNU C compiler ports almost everywhere
> and is pretty near C99 compliant.

"Almost" and "pretty near" aren't good enough for everyone's purposes.
I know gcc supports all the C99 features that *you* care about, but
that's relevant only to you.

E. Robert Tisdale

unread,
Dec 31, 2004, 10:29:35 PM12/31/04
to
Keith Thompson wrote:

> E. Robert Tisdale writes:
>
>>The GNU C compiler ports almost everywhere
>>and is pretty near C99 compliant.
>
> "Almost" and "pretty near" aren't good enough for everyone's purposes.

Nonsense!

They are good enough for C90 programmers.
C programmers accepted the new C90 standard
long before it was as mature as the C99 standard is now.
I don't see why they should hold C99 to a higher standard than C90.
Do you?

Keith Thompson

unread,
Jan 1, 2005, 12:01:54 AM1/1/05
to
"E. Robert Tisdale" <E.Robert...@jpl.nasa.gov> writes:

The issue isn't the maturity of the standard, it's how widespread
conforming implementations are. When C90 implementations were in the
state that C99 implementations are now, C90 code (particularly code
using function prototypes) still had to be considered non-portable.
It was still common to use preprocessor tricks to allow code to
compile both under K&R and C90 compilers. There was (and still is) a
tool called "ansi2knr" which translated C90 code to K&R code.

Some users were lucky enough to work in environments were they didn't
have to be concerned about portability to pre-C90 compilers, but most
of them were sensible enough not to berate those who weren't.

Stephen Sprunk

unread,
Jan 1, 2005, 3:19:45 AM1/1/05
to
"Keith Thompson" <ks...@mib.org> wrote in message
news:lnk6qxo...@nuthaus.mib.org...

> "E. Robert Tisdale" <E.Robert...@jpl.nasa.gov> writes:
> > Keith Thompson wrote:
> >> E. Robert Tisdale writes:
> >>
> >>>The GNU C compiler ports almost everywhere
> >>>and is pretty near C99 compliant.
> >> "Almost" and "pretty near" aren't good enough for everyone's
> >> purposes.

That a common implementation is not quite compliant isn't justification for
not using language features where it is compliant. I'm sure one can find
examples where GCC isn't C90 compliant either; should we go back to K&R C
until GCC is fixed?

> > Nonsense!
> >
> > They are good enough for C90 programmers.
> > C programmers accepted the new C90 standard
> > long before it was as mature as the C99 standard is now.
> > I don't see why they should hold C99 to a higher standard than C90.
> > Do you?
>
> The issue isn't the maturity of the standard, it's how widespread
> conforming implementations are. When C90 implementations were in the
> state that C99 implementations are now, C90 code (particularly code
> using function prototypes) still had to be considered non-portable.
> It was still common to use preprocessor tricks to allow code to
> compile both under K&R and C90 compilers. There was (and still is) a
> tool called "ansi2knr" which translated C90 code to K&R code.

The situation is different in this case, though, since most of the changes
in C99 were already typically implemented as extensions to C90 compilers.

> Some users were lucky enough to work in environments were they didn't
> have to be concerned about portability to pre-C90 compilers, but most
> of them were sensible enough not to berate those who weren't.

I don't berate those using C90 (or K&R) compilers because I know there are
often reasons that users don't have a choice. However, I do think it's
reasonable to code to C99 these days; the changes are minor enough that
anyone interested can back-port the code and submit patches.

Chris Croughton

unread,
Jan 1, 2005, 8:07:44 AM1/1/05
to
On Fri, 31 Dec 2004 14:32:58 -0600, Stephen Sprunk
<ste...@sprunk.org> wrote:

> "Emmanuel Delahaye" <em...@YOURBRAnoos.fr> wrote in message
> news:mn.fa7d7d4cc...@YOURBRAnoos.fr...
>> Your are correct in theory, but the C-compilers installed on zillions
>> of machines across the world and not magically going to switch to C99
>> just because a new release of the language came out...
>
> By that argument we should all still be writing in K&R C instead of C89; one
> must draw a line somewhere, and it's perfectly valid in many cases to make
> it C99 (or C89 with very common extensions).

It's perfectly valid in many cases to assume GCC with its extensions
(indeed, much of my code has done), or in other cases to assume that you
have a POSIX comlpiant library (a fair bit of my code assumes that),
etc. However, if you need to make your code maximally portable you need
to assume the minimum standard. This is why a fair bit of code still
uses compiler tricks for function prototypes, because there are still
some systems with only K&R1 compilers (as I recall the compiler supplied
on SunOS systems was barely K&R, it just sufficed to compile GCC but
probably wouldn't even do that with recent versions of GCC). In
practice, assuming C89 is pretty safe by now (15 years after the
standard came out).

There are a number of extensions in C99 which I would like to use, but
can't until C99 compilers get a lot more common (in particular GCC is
still not fully C99 compliant, in particular some of the functions and
headers have chunks of "not implemented yet" in them).

Not everyone has the choice of what compiler they use, many places won't
allow other software to be insttalled (and even when they do there is no
point in one person using a C99 compiler when the rest of the company is
using a C89 one and the code is required to be used by others!). I
doubt if many places are still using a pre-C89 compiler for any serious
development, but I know of none who are using a fully-compliant C99
compiler (indeed, from recent discussions here it seems that there isn't
one yet apart from possibly Comeau/Dinkumware, but their website says
only that it is "as close as you can get to full compliance", not that
it is fully compliant).

Chris C

Randy Howard

unread,
Jan 1, 2005, 2:33:01 PM1/1/05
to
In article <cr26gn$it0$1...@nntp1.jpl.nasa.gov>, E.Robert...@jpl.nasa.gov
says...

> Yan wrote:
>
> > A lot of times when reading open software,
> > I come across macros that are defined as follows:
> >
> > #define CALL_FUNCS(x) \
> > do { \
> > func1(x); \
> > func2(x); \
> > func3(x); \
> > } while (0);
>
> This practice is obsolete and should be discouraged.

Will you never stop?

0 new messages