Use of do...while(0) in ASSERT macro

M

Martin

Can anyone help with a quick query...

I've seen the ASSERT macro defined as:


#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \


When I comple this in debug mode the compiler warns "conditional
expression is constant", because of the while (0). Why is the ASSERT
macro defined this way? The loop only runs once so why not get rid of
the do..while and use:


#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \


This also gets rid of the compiler warning.

Is there any reason to use the first definition?

Martin
 
D

Derk Gwen

(e-mail address removed) (Martin) wrote:
# Can anyone help with a quick query...
#
# I've seen the ASSERT macro defined as:
#
#
# #define ASSERT(f) \
# do { \
# if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
# FatalExit (0); \
# } while (0) \
#
#
# When I comple this in debug mode the compiler warns "conditional
# expression is constant", because of the while (0). Why is the ASSERT
# macro defined this way? The loop only runs once so why not get rid of
# the do..while and use:
#
#
# #define ASSERT(f) \
# if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
# FatalExit (0); \

Why not try something like
if (p)
ASSERT(q)
else
s;
and see what happens.

You can prevent this by bracing
#define ASSERT(f) {\
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); }
but now you have to remember that although ASSERT(q) looks like a statement,
if you put a ';' after it
if (p)
ASSERT(q);
else
s;
it breaks unexpectedly.

Now try the original definition of ASSERT in the above.

# This also gets rid of the compiler warning.

So does the right -w option.
 
A

ANNE Alexis

Martin said:
Can anyone help with a quick query...

I've seen the ASSERT macro defined as:


#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \


When I comple this in debug mode the compiler warns "conditional
expression is constant", because of the while (0). Why is the ASSERT
macro defined this way? The loop only runs once so why not get rid of
the do..while and use:


#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \


This also gets rid of the compiler warning.

Is there any reason to use the first definition?

I don't know how it's call in english, so I try to explain it.
It because "effets de bord" tha are problem due to what we can find just
before an after the use of this macro.
In some cases, one part of the macro is included in something we don't want
to.

example:
# define ADD(A, B) A + B

ADD(1, 2) * 3 get after preprocessing: 1 + 2 * 3
or I'm sure you want: (1 + 2) * 3

so, we prefer to use:
#define ADD(A, B) ((A) + (B))

When you use function, you can use the do { blablabla } while (0) that is
the same thing, addapted to function.


I hope you'll understand however my bad english.
 
M

Mark Gordon

On 15 Nov 2003 03:34:20 -0800
Can anyone help with a quick query...

I've seen the ASSERT macro defined as:


#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \


When I comple this in debug mode the compiler warns "conditional
expression is constant", because of the while (0). Why is the ASSERT
macro defined this way? The loop only runs once so why not get rid of
the do..while and use:


#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \


This also gets rid of the compiler warning.

Is there any reason to use the first definition?

if (x)
for (y=x; y>0 && a[x]!=TARGET]; y--)
ASSERT(a[x]==BAD);
else
y=-1;

Given your definition (minus spurious \) this expands to
if (x)
for (y=x; y>0 && a[x]!=TARGET]; y--)
if (!(a[x]==BAD) && assertFailedOnLine (THIS_FILE, __LINE__))
FatalExit (0);;
else
y=-1;

Note the two semicolons after FatalExis(0) which makes the else invalid.
Get rid of the spurious semicolon you get
if (x)
for (y=x; y>0 && a[x]!=TARGET]; y--)
if (!(a[x]==BAD) && assertFailedOnLine (THIS_FILE, __LINE__))
FatalExit (0);
else
y=-1;

which makes the else associate with the if from the assert macro. Given
the original definition you get

if (x)
for (y=x; y>0 && a[x]!=TARGET]; y--)
do { \
if (!(a[x]==BAD) && assertFailedOnLine (THIS_FILE, __LINE__))
FatalExit (0);
} while (0);
else
y=-1;

which will behave as expected.

This is why you will see people using do { ... } while (0) in macros
when they want something that behaves like a function with a return type
of void. Also note the lack of a semicolon at the end of the macro
definition.
 
N

Nudge

ANNE said:
I don't know how it's call in english, so I try to explain it. It
because "effets de bord" tha are problem due to what we can find
just before an after the use of this macro.

Hello petit Jean Kevin de la porte d'Ivry :)

"Effets de bord" is the (unfortunate) French translation for "side
effects". It should, instead, have been translated to "effets
secondaires".
 
P

pete

Martin said:
Can anyone help with a quick query...

I've seen the ASSERT macro defined as:

#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \
#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \

If you place a backslash as the last character
in the last line of a macro, then,
it is no longer the last line of the macro.
 
J

James Hu

#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \
vs...

#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \

Is there any reason to use the first definition?

This is a comp.lang.c FAQ. Please read the answer to question 10.4 of
the C-faq.

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

-- James
 
C

Christian Bau

Can anyone help with a quick query...

I've seen the ASSERT macro defined as:


#define ASSERT(f) \
do { \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \
} while (0) \


When I comple this in debug mode the compiler warns "conditional
expression is constant", because of the while (0). Why is the ASSERT
macro defined this way? The loop only runs once so why not get rid of
the do..while and use:


#define ASSERT(f) \
if (!(f) && assertFailedOnLine (THIS_FILE, __LINE__)) \
FatalExit (0); \


This also gets rid of the compiler warning.

Is there any reason to use the first definition?

Try compiling this:

if (x >= 0)
ASSERT (x <= 10);
else
ASSERT (x >= -10);
 
R

Richard Heathfield

Christian said:
Try compiling this:

if (x >= 0)
ASSERT (x <= 10);
else
ASSERT (x >= -10);

Another excellent argument for using { } every time.

#define ASSERT(f) \
if (!(f) && assertFailedOnLine(__FILE__, __LINE__)) \
FatalExit (0);

if(x >= 0)
{
ASSERT(x <= 10);
}
else
{
ASSERT(x >= -10);
}

....works just fine without the do/while(0) silliness.
 
C

Christopher Benson-Manica

Richard Heathfield said:
...works just fine without the do/while(0) silliness.

Does that mean that the do/while(0) bit is merely an obfuscating
device?
 
J

Jeremy Yallop

Christopher said:
Richard Heathfield <[email protected]> spoke thus: [
#define ASSERT(f) \
if (!(f) && assertFailedOnLine(__FILE__, __LINE__)) \
FatalExit (0); ]
...works just fine without the do/while(0) silliness.

Does that mean that the do/while(0) bit is merely an obfuscating
device?

No. It is a device to increase the robustness of the code. Without
the do/while wrapper the macro will work in certain circumstances, but
have silently incorrect behaviour if used as the body of a braceless
"if" statement (which has a matching "else"). In this particular case
the macro /can/ be written to have the correct behaviour without
do/while:

#define ASSERT(f) \
(void)((!f || assertFailedOnLine(__FILE__, __LINE__)) && (FatalExit(0), 0))

but if the macro must expand to multiple /statements/ then the
do/while trick (or something similar) is needed for the macro to have
the correct behaviour.


Jeremy.
 
R

Richard Heathfield

Christopher said:
Does that mean that the do/while(0) bit is merely an obfuscating
device?

If you write:

if(foo)
bar();

then no, it is not.

If you write:

if(foo)
{
bar();
}

then yes, it is.
 
C

Christian Bau

Christopher Benson-Manica said:
Does that mean that the do/while(0) bit is merely an obfuscating
device?

It is an extremely widespread idiom that is commonly used by many
programmers when they write macros that look like function calls and
that are intended to behave like function calls as much as possible.

It is certainly hard to understand what it is good for the first time
you see it, but once a new C programmer has understood it, it is easy to
recognise and easy to use.
 
C

Christian Bau

Richard Heathfield said:
If you write:

if(foo)
bar();

then no, it is not.

If you write:

if(foo)
{
bar();
}

then yes, it is.

If you think that removing the braces in
if(foo)
{
bar();
}

shouldn't cause any problems, then it isn't.
 
R

Richard Heathfield

Christian said:
If you think that removing the braces in


shouldn't cause any problems, then it isn't.

But if you aren't ever going to do that, because you'd rather gnaw off your
own leg than use a single-statement if, then it is.

Over to you, Christian. :)
 
A

Alex

Richard Heathfield said:
Christian Bau wrote:
But if you aren't ever going to do that, because you'd rather gnaw off your
own leg than use a single-statement if, then it is.

But if the person maintaining your code is not in the same
state of mind?

Alex
 
R

Richard Heathfield

Alex said:
But if the person maintaining your code is not in the same
state of mind?

Then I'd be beside myself. :)

Seriously, it's a reasonable point, but in my defence[1] I generally do my
level best to get the coding standards at a client site changed to mandate
compound statements if they don't already do so. I've had some degree of
success with this. :)
 

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

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top