do{..}while(0) macro substitutions

Y

Yan

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
 
B

Ben Pfaff

Yan said:
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.
 
A

Alexandre

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
 
A

Andrey Tarasevich

Yan said:
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.

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).
 
I

italy

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."
 
E

E. Robert Tisdale

Yan said:
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);
}
 
F

Flash Gordon

Yan said:
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.

Try things like:

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

and see how far you get.
 
K

Keith Thompson

italy said:
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.
 
K

Keith Thompson

E. Robert Tisdale said:
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);
}

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.
 
E

E. Robert Tisdale

Keith said:
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.
 
M

Mysidia

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

Emmanuel Delahaye

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"
 
E

Emmanuel Delahaye

E. Robert Tisdale wrote on 31/12/04 :
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);
}

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

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

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

Raymond Martineau

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.
 
E

Emmanuel Delahaye

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.

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

"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++
 
S

Stephen Sprunk

Emmanuel Delahaye said:
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
 
K

Keith Thompson

Stephen Sprunk said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top