Why the usage of while(0)

  • Thread starter Riccardo Manfrin
  • Start date
R

Riccardo Manfrin

Hi list!
Having this code:
do {
if (flag_prg)
printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
} while (0)

why the use of while?
R
 
B

Ben Bacarisse

[This shoudl be a FAQ but I can't currently check since the C FAQ site
appears to be down.]
Having this code:
do {
if (flag_prg)
printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
} while (0)

why the use of while?

As you present it, none. In fact it's a syntax error since there is
no ; after the while (0). This is a big clue that the code comes
from a macro.

The purpose of the loop is syntactic. It encloses the 'if' in a
statement (when the ; is added by the macro invocation) so that no
surprises happen to the users of the macro. Consider the simpler:

#define PRINT_BANNER if (flag_prg) \
printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER)

and a usage like this:

if (first_run)
PRINT_BANNER;
else puts("Going again...";

The 'else' will be taken to be part of the inner if regardless of the
indentation. do {} while (0) gets round this and other potentials
problems with macros that expand to statements.
 
R

Riccardo Manfrin

Thanks both Ben & pete!
mymistake not stating that was code within a #define statement.
Thanks for the explaination. Now I know the reason why.
R
 
K

Kaz Kylheku

Hi list!
Having this code:
do {
if (flag_prg)
printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
^
Typo? Strange to have a lower case letter on the end of an all-caps
macro. I take it this is a plural, implying that expands into a
string literal containing two numbers separated by a period,
specifying the width an pecision for %s?
} while (0)

why the use of while?

That allows the whole thing to be a syntactically encapsulated statement
which requires a terminating semicolon, which is useful if it is
the expansion of a macro.

Suppose that you drop the do/while(0) and your macro just
expands this (note dropped semicolon).

if (flag_prg)
printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER)

Unlike do/while(0) this has problems. For instance, you can now
do something like this:

MACRO() + 3;

The + 3 happily goes onto the printf, so that it's obvious that MACRO()
is not a proper statement. But is it an expression? If so, this
should work:

var = MACRO();

but, nope, that breaks! You're assigning the value of an if statement,
oops!

Moreover, here is the kicker:

MACRO()
else { ... }

Look ma, you can continue the if statement that is started within the
macro expansion, by adding an else, and there is no compiler diagostic.

So you see this do/while(0) wrapping protects against crap like this.

Another good question is, why the cryptic compile-time string literal
manipulation instead of something straightforward, like:

prinf("%-*.*s", PROGNAME_WIDTH, PROGNAME_LIMIT, PROGNAME_BANNER);

A conversion like

"%-42.40s", string

isn't necessarily faster than

"%*.*s", width, prec, string

the reason is that if the format string is being interpreted, then the
42 and 40 have to be scanned and turned into values. Whereas the *
character allows printf to simply retrieve a ready-made integer value
from the arguments; no text-to-int conversion necessary.

You might have a performance win here if your your implementation has a
printf compiler which turns format strings into code.

Also, what is the purpose of this juxtaposition:

" " PROGNAME_BANNER

The extra space can easily be added under the control of the printf
format string. It's silly to be adding padding to the data.

Rather than "%s", " " MY_STRING you can just " %s", MY_STRING.
 
J

James Dow Allen

        do {
....
        } while (0)

I once scanned through glibc source looking for instances of
this construction. I may as well report my results.

In
glibc-2.7/soft-fp/testit.c
there is, *inside* a switch block,
do {
case 'a': r = r_addsf3; t = ...; break;
case 's': r = r_subsf3; t = ...; break;
case 'm': r = r_mulsf3; t = ...; break;
case 'd': r = r_divsf3; t = ...; break;
case 'r': r = r_sqrtsf3; t = ...; break;
case 'j': r = r_negsf3; t = ...; break;
} while (0);
Although in a switch the "break"s here just break out of the
do while (0). In other words, the peculiar "do break while"
simply avoids what some of us would accomplish with
"goto commoncode;" I'd be interested to hear whether
anti-goto fanatics are fans of the above construction!

Another place where do while(0) was introduced, seemingly
just to avoid goto is in
nptl/pthread_mutex_setprioceiling.c
"break" and "continue" have, I think, *identical* meaning
inside the while(0); yet the code just mentioned uses
each of them! (Perhaps this is a vestigial remnant of
earlier version where the while predicate was other
than just 0.)

BTW, I also found *many* instances of the usual
do {...} while(0) macros, as well as two instances
argp/argp-help.c
elf/readelflib.c
with "while (0);" terminating the macro! I assume the
extra ";" were typos, not causing trouble since the
macros weren't used inside if or other troublesome cases.

James Dow Allen
 
E

Eric Sosman

James said:
I once scanned through glibc source looking for instances of
this construction. I may as well report my results.

In
glibc-2.7/soft-fp/testit.c
there is, *inside* a switch block,
do {
case 'a': r = r_addsf3; t = ...; break;
case 's': r = r_subsf3; t = ...; break;
case 'm': r = r_mulsf3; t = ...; break;
case 'd': r = r_divsf3; t = ...; break;
case 'r': r = r_sqrtsf3; t = ...; break;
case 'j': r = r_negsf3; t = ...; break;
} while (0);
Although in a switch the "break"s here just break out of the
do while (0). In other words, the peculiar "do break while"
simply avoids what some of us would accomplish with
"goto commoncode;" I'd be interested to hear whether
anti-goto fanatics are fans of the above construction!

If each `break' were changed to `continue', the code
would do the same thing but might be less susceptible to
mis-reading.

One wonders, though, why the "more natural" arrangement

switch (whatever) {
case 'a': r = ...; break;
case 's': r = ...; break;
...
}
... common code ...

wasn't used. Maybe the "common" code applies only to some
of the `switch' cases, and not to all? (That is, does the
`switch' have additional `case's outside the `do'?)
 
A

Antoninus Twink

Maybe the "common" code applies only to some of the `switch' cases,
and not to all? (That is, does the `switch' have additional `case's
outside the `do'?)

Presumably that's the whole point.
 
K

Kaz Kylheku

Presumably that's the whole point.

Yeah, well Sosman wouldn't just assume that people maintaining glibc
might have a point, right?

I am sure Drepper would never accept a patch containing weird code like
that unless there was a very good reason why it's done that way.
Avoding a ton of forward gotos is apparently such a reason.

That code is a big switch, with a number of repetitions of
the do/while(0) idiom.

It's the perfect iditom in the situation in which the switch cases group
into subsets, to which common code applies, but which also have to do
something unique for each member case.
 
J

James Dow Allen

James said:
In
   glibc-2.7/soft-fp/testit.c
there is, *inside* a switch block,
          do {
             case 'a': r = r_addsf3; t = ...; break;
             case 's': r = r_subsf3; t = ...; break; . [snip]
          } while (0);
Although in a switch the "break"s here just break out of the
do while (0).  In other words, the peculiar "do break while"
simply avoids what some of us would accomplish with
"goto commoncode;"  I'd be interested to hear whether
anti-goto fanatics are fans of the above construction!

One wonders, though, why the "more natural" arrangement
...
wasn't used.  Maybe the "common" code applies only to some
of the `switch' cases, and not to all?

Yes, sorry I didn't make this clear.

Actually there were three or so of these do while (0)'s
all within the same giant switch block. Moreover, there
were other blocks nesting between the switch and the do while's:
blocks just to declare local automatic variables.

This was all inside main() in a function named testit.c
so I suppose stylistic perfectionism is relaxed. Still
I would like to hear an answer to my question:
What do anti-goto fanatics think of this method of
avoiding goto?

James Dow Allen
 
A

Antoninus Twink

I would like to hear an answer to my question: What do anti-goto
fanatics think of this method of avoiding goto?

Are there many anti-goto fanatics left? I thought most people nowadays
had grown up and taken a less dogmatic and more pragmatic approach to
programming.

(Heathfield is an obvious example of course - no position is too
ridiculous for him. I believe he also objects to having more than one
return statement in a function.)
 
E

Eric Sosman

Kaz said:
Yeah, well Sosman wouldn't just assume that people maintaining glibc
might have a point, right?

I asked "X?" I did not assert or imply either "X" or "!X",
and anyone who assumes I did so is making an unfounded assumption.
 
E

Eric Sosman

James said:
[...] Still
I would like to hear an answer to my question:
What do anti-goto fanatics think of this method of
avoiding goto?

Since anyone who answers implicitly asserts that he
is in fact a "fanatic," there may be some reluctance to
respond ...
 
J

James Dow Allen

.
Since anyone who answers implicitly asserts that he
is in fact a "fanatic," there may be some reluctance to
respond ...

Sorry again; this superfluous pejorative was
uncalled-for. But surely comments from any
c.l.c'ers are welcome; admission or denial of
fanaticism is optional. :)

(Given that some c.l.c'ers proudly embrace the
term "Pedant", I'd not be surprised if some happily
acknowledge fanaticism. Probably I could be accused
of fanaticism on some topics; e.g. refusal to
issue blanket condemnation of 'goto'. :)

But anyway, this particular usage of
do {
... break;
... continue;
} while (0);
to avoid 'goto commoncase;' is uninteresting compared
to the goto in
http://james.fabpedigree.com/gotoalt.htm

I *do* hope c.l.c'ers will read that page and comment.
So far only two votes have been recorded:
Tim votes for Tim's code.
James votes for James' code.
Others? (I'm tempted to confess, in another thread,
that I use 'goto' in transition-machine code, but
may not dare unless I get some votes in *this* poll.)

James Dow Allen
 
F

Flash Gordon

James said:
Sorry again; this superfluous pejorative was
uncalled-for. But surely comments from any
c.l.c'ers are welcome; admission or denial of
fanaticism is optional. :)

I'm not fanatical, but I have seen code which is horrendous in part due
to the use of goto.
(Given that some c.l.c'ers proudly embrace the
term "Pedant", I'd not be surprised if some happily
acknowledge fanaticism. Probably I could be accused
of fanaticism on some topics; e.g. refusal to
issue blanket condemnation of 'goto'. :)

But anyway, this particular usage of
do {
... break;
... continue;
} while (0);

I've used that kind of pattern. I've also used a pattern of..

static int dirtyfoo(params)
{
ret = ok
do stuff
if error return notsolateerror

do stuff
if error return verylateerror

do stuff

return OK
}

int foo(params)
{
ret = dirtyfoo(params)
switch (ret) {
case verylateerror: clean up late stuff
case notsolateerror: clean up not so late stuff
...
}
return ret;
}

The cleanup stuff here was sending appropriate cleanup bits to an
external system over a socket. The goto type alternative would have been

int foo(params)
{
do stuff
if error { ret = notsolateerror; goto notsolateerror }
do stuff
if error { ret = verylateerror; goto verylateerror }
do stuff
return OK

verylateerror:
clean up late stuff
notsolateerror:
clean up not so late stuff
return ret
}

There were actually a hole load of sub functions, with sub functions,
all returning statuses, with the status codes selected to I could just
propagate them out to the external caller.

I think my splitting out the work in to a sub-functions and abusing a
switch for the cleanup worked well, especially as there was no cleanup
if it was all OK.
to avoid 'goto commoncase;' is uninteresting compared
to the goto in
http://james.fabpedigree.com/gotoalt.htm

I *do* hope c.l.c'ers will read that page and comment.
So far only two votes have been recorded:
Tim votes for Tim's code.
James votes for James' code.
Others?

I would have to think hard about it, but it feels like some kind of
recursive solution might be cleaner. Possibly a function for each of the
loops in the first block, with the loop done by a recurse in each case,
the retract done on the unwind with, of course, a done result allowing
you to unwind without retracting. I'm not up to working it out at the
moment, in part due to not understanding the problem being solved by it.
(I'm tempted to confess, in another thread,
that I use 'goto' in transition-machine code, but
may not dare unless I get some votes in *this* poll.)

Well, I've used loops, switches and state variable for state machines
where others use gotos in the past. I seem to remember also using a
function table and state variable once for a state machine...
initialise state
loop
state = call action[state]
until state is finished
so each function in the action array returned the next state, all nicely
named with an enum.

I will use goto sometimes, mainly for exception handling.
 
N

Nick

James Dow Allen said:
Actually there were three or so of these do while (0)'s
all within the same giant switch block. Moreover, there
were other blocks nesting between the switch and the do while's:
blocks just to declare local automatic variables.

I do the latter, although I'm never very happy about it:
switch(a) {
case 10:
{
int p,r,s;
... do stuff with p,r and s ...
break;
}
case 11:
}

In a really fiddling point of style, I often wonder which side of close
brace the "break" should be.
 
G

Guest

|
| [This shoudl be a FAQ but I can't currently check since the C FAQ site
| appears to be down.]
|
|> Having this code:
|> do {
|> if (flag_prg)
|> printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
|> } while (0)
|>
|> why the use of while?
|
| As you present it, none. In fact it's a syntax error since there is
| no ; after the while (0). This is a big clue that the code comes
| from a macro.
|
| The purpose of the loop is syntactic. It encloses the 'if' in a
| statement (when the ; is added by the macro invocation) so that no
| surprises happen to the users of the macro. Consider the simpler:
|
| #define PRINT_BANNER if (flag_prg) \
| printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER)
|
| and a usage like this:
|
| if (first_run)
| PRINT_BANNER;
| else puts("Going again...";
|
| The 'else' will be taken to be part of the inner if regardless of the
| indentation. do {} while (0) gets round this and other potentials
| problems with macros that expand to statements.

Do you have an example where enclosing in plain { } is not good enough?
 
G

Guest

| On 5 Dec 2009 at 18:59, James Dow Allen wrote:
|> I would like to hear an answer to my question: What do anti-goto
|> fanatics think of this method of avoiding goto?
|
| Are there many anti-goto fanatics left? I thought most people nowadays
| had grown up and taken a less dogmatic and more pragmatic approach to
| programming.

What is the difference between an anti-goto fanatic and an anti-goto
advocate?

What about the anti-goto-into-the-middle-of-a-loop fanatics?
 
J

James Dow Allen

.
I would have to think hard about it, but it feels like some kind of
recursive solution might be cleaner....

You could be right (though perhaps a somewhat different
recursion than you outline), and end up with code more
readable than either James' or Tim's, though somewhat slower.
I'm not sure how much slowdown would be acceptable while
still conceding superiority.

But only Tim and James have taken the time to actually
produce working code. *If you're forced to choose
between these two versions*, which would you pick?

James
 
P

Phil Carmody

Nick said:
switch(a) {
case 10:
{
int p,r,s;
... do stuff with p,r and s ...
break;
}
case 11:
}

In a really fiddling point of style, I often wonder which side of close
brace the "break" should be.

case pairs with break, as the case is outside the {, the break
should be outside the }. I find that observance of that to be
very rare compared to the style you quote.

Phil
 
B

Ben Bacarisse

| Riccardo Manfrin <[email protected]> writes:
|> Having this code:
|> do {
|> if (flag_prg)
|> printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
|> } while (0)
|>
|> why the use of while?
| The purpose of the loop is syntactic. It encloses the 'if' in a
| statement (when the ; is added by the macro invocation) so that no
| surprises happen to the users of the macro. Consider the simpler:
|
| #define PRINT_BANNER if (flag_prg) \
| printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER)
|
| and a usage like this:
|
| if (first_run)
| PRINT_BANNER;
| else puts("Going again...";

I missed a ) but that is not significant.
| The 'else' will be taken to be part of the inner if regardless of the
| indentation. do {} while (0) gets round this and other potentials
| problems with macros that expand to statements.

Do you have an example where enclosing in plain { } is not good
enough?

The example I gave is already one -- the usage becomes complex.
PRINT_BANNER is now different (syntactically) to PRINT_BANNER;
 

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,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top