Help understanding this use of while

C

Chris Saunders

I saw this code and don't understand this use of while. It seems to me
that the while loop will just occur once but then why use a while loop
at all? Here's the code:

#define SWAP_PTRS(x_dummy_p, y_dummy_p) \
do { \
fmpz_t swap_temp_p = x_dummy_p; \
x_dummy_p = y_dummy_p; \
y_dummy_p = swap_temp_p; \
} while(0);

Regards
Chris Saunders
 
B

Barry Schwarz

I saw this code and don't understand this use of while. It seems to me
that the while loop will just occur once but then why use a while loop
at all? Here's the code:

#define SWAP_PTRS(x_dummy_p, y_dummy_p) \
do { \
fmpz_t swap_temp_p = x_dummy_p; \
x_dummy_p = y_dummy_p; \
y_dummy_p = swap_temp_p; \
} while(0);

It allows you to generate constructs such as
if (x) SWAP_PTRS(y,z)

Think about what would happen if the macro did not contain the "do"
and "while" lines.
 
B

Ben Bacarisse

Chris Saunders said:
I saw this code and don't understand this use of while. It seems to
me that the while loop will just occur once but then why use a while
loop at all? Here's the code:

#define SWAP_PTRS(x_dummy_p, y_dummy_p) \
do { \
fmpz_t swap_temp_p = x_dummy_p; \
x_dummy_p = y_dummy_p; \
y_dummy_p = swap_temp_p; \
} while(0);

It is (as pete has pointed out) a mistake. The usual case is without
the final ;. The logic goes like this:

You want a macro that has a declaration. You need a block for that.
If you write this:

#define SWAP(a,b) { T t=a; a=b; b=t; } /* ()s omitted for clarity */

then things go wrong if you write:

if (C)
SWAP(x, y);
else something_else();

Expand SWAP and look closely and you will see am empty statement
before the else. This is not valid syntax. So, what construct in C
has a block but can have a trailing ; and still remain a single
statement? Ah:

#define SWAP(a,b) do { T t=a; a=b; b=t; } while (0)

Now SWAP(x,y); is a correct, single statement.

If you don't omit the trailing ; from the macro, you might as well
just use a plain block and avoid the odd looking do ... while (0).
 
K

Keith Thompson

Chris Saunders said:
I saw this code and don't understand this use of while. It seems to
me that the while loop will just occur once but then why use a while
loop at all? Here's the code:

#define SWAP_PTRS(x_dummy_p, y_dummy_p) \
do { \
fmpz_t swap_temp_p = x_dummy_p; \
x_dummy_p = y_dummy_p; \
y_dummy_p = swap_temp_p; \
} while(0);

This is question 10.4 of the comp.lang.c FAQ, <http://www.c-faq.com/>.
 
B

Ben Bacarisse

Barry Schwarz said:
It allows you to generate constructs such as
if (x) SWAP_PTRS(y,z)

Think about what would happen if the macro did not contain the "do"
and "while" lines.

True, but if the author of the macro intended the user of it do the
above (i.e. to watch his of her semicolons like a hawk) then what is
the point of the 'do' and the 'while(0);' -- i.e. why not just use a
block? It would be simpler and raise fewer questions. The whole
point of the do ... while (0) trick is to introduce a block that is
just one semicolon short of a full statement.
 
C

CBFalconer

Chris said:
I saw this code and don't understand this use of while. It seems
to me that the while loop will just occur once but then why use a
while loop at all? Here's the code:

#define SWAP_PTRS(x_dummy_p, y_dummy_p) \
do { \
fmpz_t swap_temp_p = x_dummy_p; \
x_dummy_p = y_dummy_p; \
y_dummy_p = swap_temp_p; \
} while(0);

Leave off the final ';'. Then the macro acts normally in all code.
e.g.:

if (something) SWAP_PTRS(x, y);
else {
/* other code */
}
 
L

Lew Pitcher

C doesn't allow bare blocks.

Hmmmm.... what do you mean by that? Why doesn't a C "compound statement"
qualify as a "bare block"?

So if you have a multi-line macro, and a
controlling statement

eg

#define MYMACRO() printf("Hello");printf("World");
if(x == y)
MYMACRO();

"World" will be printed if x != y, which probably isn't what you want.

OTOH, if the macro were
#define MYMACRO() { printf("Hello"); printf("World"); }
then
if (x==y)
MYMACRO();
would work as expected.
The do ... while(0) is a hack to get round that oversight. It works very
well.

I think that you really wanted to illustrate
if (x == y)
MYMACRO();
else
do_something_else();

If MYMACRO() expanded to a full statement (either a semi-colon terminated
single statement, or a brace bracketed compound statement), the trailing
semicolon from the unexpanded invocation (the semicolon at the end
of "MYMACRO();") would be taken as a new (empty) statement at the same
level as the "if" statement.

This, in turn, would "unpair" the following "else" statement from the "if"
statement, causing a syntax error upon compilation.

The "do { } while(0)" macro expansion takes advantage of the syntax of the
do/while verb, along with the behaviour of the while(0) condition, to
permit a single pass through the "do {} while()" logic (like the compound
statement would permit), while permitting (requiring) the macro invocation
to be treated as a single statement, terminated with a semicolon. Thus, the
semicolon that follows the MYMACRO() invocation is paired with the while()
clause of the expanded macro, and the "else" is left to be properly paired
with the preceding "if".

The drawback to using a "do {} while(0)" macro is that the invocation /must/
be terminated with a semicolon. This means that it is /not/ proper to use
this sort of macro as anything other than the rightmost rvalue of a
statement. In other words, you can't use it as
a = MYMACRO() + 6;
or even
a = MYMACRO(), 10;

--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
 
P

Phil Carmody

Malcolm McLean said:
C doesn't allow bare blocks.

What's that supposed to mean?

#include <stdio.h>
int main()
{
{
int ImInABareBlock=1;
printf("He's in a bare block - %i", ImInABareBlock);
}
}

Quite how you'd like that bare block to be adorned in order
to be not allowed, I don't know, but I suspect it'd not be
sensibly called a bare block afterwards.

Phil
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top