why the use of while?
R
#define MACRO do{X}while(0)
This makes X be the body a compound statement,
and it forces MACRO to be semicolon terminated
like a simple statement whenever MACRO is used.
MACRO;
--
pete
[This shoudl be a FAQ but I can't currently check since the C FAQ site
appears to be down.]
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.
--
Ben.
> } 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.
Actually, the real kicker is code like:
if (condition)
MACRO();
else
printf( "condition was false\n" );
Without the do/while(0), the compiler will accept this without complaint,
but assign the wrong meaning to it.
--
poncho
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
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'?)
--
Eric Sosman
eso...@ieee-dot-org.invalid
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.
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
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.)
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.
--
Eric Sosman
eso...@ieee-dot-org.invalid
Since anyone who answers implicitly asserts that he
is in fact a "fanatic," there may be some reluctance to
respond ...
--
Eric Sosman
eso...@ieee-dot-org.invalid
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
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.
--
Flash Gordon
> 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.
--
Online waterways route planner: http://canalplan.org.uk
development version: http://canalplan.eu
Do you have an example where enclosing in plain { } is not good enough?
--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
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
| 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?
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
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1
> On Fri, 04 Dec 2009 13:14:00 +0000 Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
> | Riccardo Manfrin <names...@guesswhat.guesswhat> writes:
<snip>
> |> Having this code:
> |> do {
> |> if (flag_prg)
> |> printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER);
> |> } while (0)
> |>
> |> why the use of while?
<snip>
> | 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;
--
Ben.
> On Fri, 04 Dec 2009 13:14:00 +0000 Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
> | Riccardo Manfrin <names...@guesswhat.guesswhat> writes:
> |
> | [This shoudl be a FAQ but I can't currently check since the C FAQ site
> | appears to be down.]
It is. 10.4 in the text version on my computer.
> |> 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?
Yes: the one above. If you wrote
#define PRINT_BANNER { statements... }
then
if (first_run)
PRINT_BANNER;
else
puts("Going again...");
would result in
if (first_run)
{ statements... };
else
puts("Going again...");
which, because of the extra semicolon, is a syntax error.
If, OTOH, you write
#define PRINT_BANNER do { statements... } while (0)
then
PRINT_BANNER;
is a single, valid statement, which will run once and only once, in any
context where a normal single-line statement would have done so -
including the above if-else statement (try it!).
Richard
If you use
#define MACRO (flag_prg ? printf("%-" PROGNAME_WIDTHs "s"," "
PROGNAME_BANNER) : 0)
you can also use it where you need an expression, e.g. in the
‘initialization’ of a for loop.
--
Armando di Matteo <a r m y ONE NINE EIGHT SEVEN AT e m a i l DOT i t>
Vuolsi così colà dove si puote / ciò che si vuole; più non dimandare.
[ T H I S S P A C E I S F O R R E N T ]
Flash Gordon wrote:
> I will use goto sometimes, mainly for exception handling.
I uses goto for jumping out of multi-level loops (for the purpose of Java's
labelled breaks or continues).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
iEYEARECAAYFAksjrm4ACgkQG6NzcAXitM9dxQCdHMWx5hIgVR78vq/72aA0qySd
WTgAnRKby8ldSku3+KMfDU1ZdKK7uhtI
=MyJQ
-----END PGP SIGNATURE-----
> [snip]
>
> 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 must post a correction here. The code attributed to
me on this page is not something I wrote. I did write
something on a related subject (in c.l.c IIRC), but
that was written for a different context. No poor
reflection on James intended, I'm sure it was an honest
mistake; but I need to set the record straight that
the writing isn't mine nor was I intending to make
comments in the context this web page provides.
Tim posted pseudo-code several years ago in Usenet message
kfn64vh...@alumnus.caltech.edu
known to Google via
http://groups.google.com/group/comp.lang.c/msg/d2882f5a6bb1b999?dmode=source
This pseudo-code was specifically in response to my webpage
code. I did edit it slightly (I hope Tim will
point out which change he objects to; glancing at it
now I see little change beyond white space and
capitalization rearrangements.) I mentioned to Tim,
via e-mail, that I intended to post the code; and did
not receive any objection from Tim. This was almost 5
years ago. I can't fault Tim's memory: I barely remember
what I had for brerakfast yesterday! :-)
What *is* true, of course, is that in the comments
on my page I defended my approach over Tim's.
I *am* disappointed that no one else has bothered to
"vote" for one approach over the other. The vote
still stands at 1-1 ....
I will remove the code or the attribution at Tim's request.
(I hunted to find parts of my e-mail exchange with Tim which
was at a Yahoo e-mail I use no more. My present e-mail
is jamesdowallen at Gmail.)
Thank you.
James Dow Allen
> On Jan 13, 12:22 am, Tim Rentsch <t...@alumni.caltech.edu> wrote:
>> James Dow Allen <jdallen2...@yahoo.com> writes:
>> > to avoid 'goto commoncase;' is uninteresting compared
>> > to the goto in
>> > http://james.fabpedigree.com/gotoalt.htm
>>
>> I must post a correction here. The code attributed to
>> me on this page is not something I wrote.
>
> Tim posted pseudo-code several years ago in Usenet message
> kfn64vh...@alumnus.caltech.edu
> known to Google via
> http://groups.google.com/group/comp.lang.c/msg/d2882f5a6bb1b999?dmode=source
>
> This pseudo-code was specifically in response to my webpage
> code.
No, it was a response to comments and discussion in the thread in
comp.lang.c. It's true that some code that James wrote formed
the backdrop for my comments, but they really were directed at
the newsgroup discussion and goto's/backtracking generally, not
meant as commentary on James's code.
> I did edit it slightly (I hope Tim will
> point out which change he objects to; glancing at it
> now I see little change beyond white space and
> capitalization rearrangements.) I mentioned to Tim,
> via e-mail, that I intended to post the code; and did
> not receive any objection from Tim. This was almost 5
> years ago. I can't fault Tim's memory: I barely remember
> what I had for brerakfast yesterday! :-)
I think you are misremembering. We did trade some emails about
the possibility of my providing some code for that purpose, but I
never did provide any such code, and I'm sure I would have raised
an objection if I thought something was going to be put up other
than something I specifically provided for that purpose.
> What *is* true, of course, is that in the comments
> on my page I defended my approach over Tim's.
>
> I *am* disappointed that no one else has bothered to
> "vote" for one approach over the other. The vote
> still stands at 1-1 ....
>
> I will remove the code or the attribution at Tim's request.
> (I hunted to find parts of my e-mail exchange with Tim which
> was at a Yahoo e-mail I use no more. My present e-mail
> is jamesdowallen at Gmail.)
The code on the webpage shouldn't be referred to as "Tim's code",
since it's not what I wrote. As long as it's clear that the
writing there isn't mine and that the comments I did make were
written for another context, it should be okay. Something like,
"In a discussion in comp.lang.c, Tim Rentsch suggested [link to
original article] code somewhat along the following lines."
If these kinds of changes are made leaving the other text
intact shouldn't be a problem.