for(;;) or while(1)?

M

Minti

Thomas Matthews said:
I didn't think this was valid syntax (after macro substitution):
do
{
/* ...x... */
} for (;;); /* after preprocessor substitution */

My understanding is the syntax is:
do
{
} while();

Nitpick: replace while() with while(expr)
I don't believe you can replace the "while" with "for" in this
syntax. I've never heard of a "do-for" loop.

Me neither. A lot of books would need to be appended if it existed.
 
M

Minti

Mike Wahler said:
for(;;) has seven characters, and
while(1) has eight, so the former should
weight slightly less, thus be a bit more
portable.

Mine for loop

for ( ; ; )

has 11 characters

so does my while

while ( 1 )

including whitespace I might add.
Also, if carrying the construct in a backback,
the rounded edges of 'f' 'o' and 'r' should
be more comfortable than those pointy 'w', 'h',
'i', and 'l' characters. :)

I guess it all boils down to this *VERY* difference only.
 
N

Noah Roberts

Richard said:
Thomas Matthews wrote:




That was, I believe, the point he was making (i.e. that for(;;) and while(1)
are not interchangeable in all cases).

Yeah, that was the point I was making. Some people like to create a
macro like that, I usually just use the actual loop when I am testing
code. I don't like to use forever loops in real code but if I where to
do so I might define something like that.
For what it's worth, I think while(condition) is clearer than either for(;;)
or while(1).

Yes, it is much better to use a condition to exit. Many times people do
something like the following:

while (always)
get input
if input is quit then die

do something
....

but it is much better do do something like this:

boolean quit = false /* or continue = true */

while (!quit)
get input
if input is quit then quit = true
else do something
....

The second version is "structured" code whereas the first is not (two
exits). Sometimes it is better to break structure, but it always
sacrifices maintainability and readability; this is why goto was
declaired to be evil, yet in some algorithms (for instance verified null
move pruning in chess AI's) it is useful.

99.9999999% of the time it is not necissary to write unstructured code
and since it is a mistake to do so you shouldn't except for that
..000000001% of the time when you need to.

NR
 
M

Mike Wahler

Minti said:
"Mike Wahler" <[email protected]> wrote in message

Mine for loop

for ( ; ; )

has 11 characters

so does my while

while ( 1 )

including whitespace I might add.


I guess it all boils down to this *VERY* difference only.

Everyone knows that whitespace characters are weightless. :)

-Mike
 
N

Noah Roberts

osmium said:
Noah Roberts writes:




I wouldn't expect the alternative to work.
Pedants, especially, should test their code before positng.

If you use continue = true you must alter the loop just slightly.

while (continue)
{

if (wanttoquit) continue = false;
else dostuff...
}

I guess some people must have it spelled out for them, I assumed too
much. And no, I was not being pedantic but you have the right to that
opinion.

NR
 
O

osmium

Noah said:
but it is much better do do something like this:

boolean quit = false /* or continue = true */

I wouldn't expect the alternative to work.
Pedants, especially, should test their code before positng.
 
N

Neil Cerutti

If you use continue = true you must alter the loop just slightly.

while (continue)
{

if (wanttoquit) continue = false;
else dostuff...
}

I guess some people must have it spelled out for them, I
assumed too much. And no, I was not being pedantic but you
have the right to that opinion.

continue is a keyword.
 
C

Chris Dollin

Noah said:
Yes, it is much better to use a condition to exit. Many times people do
something like the following:

while (always)
get input
if input is quit then die

do something
...

but it is much better do do something like this:

boolean quit = false /* or continue = true */

I'm sure that, being a well-structuring kind of chap, you just forgot
that `continue` is a C keyword ...
while (!quit)
get input
if input is quit then quit = true
else do something
...

The second version is "structured" code whereas the first is not (two
exits).

The second one is horrid. The artifical boolean variable obscures what's
going on.

Assuming `always` is well-named, the first one has on exit. N-and-a-half
loops are just as structured as N loops. The idiom

while (yourChoiceForTrue)
{ preamble;
if (doneExpression) break;
postamble; }

is well-structured and worth knowing.
Sometimes it is better to break structure, but it always
sacrifices maintainability and readability;

Not *always*.

The rule that makes sense to me is "code clearly". If it's a choice
between between being clear and being structured, being clear wins.
Usually you don't need to make the choice.
 
C

CBFalconer

Chris said:
Noah Roberts wrote:
.... snip ...

N-and-a-half loops are just as structured as N loops. The idiom

while (yourChoiceForTrue)
{ preamble;
if (doneExpression) break;
postamble; }

is well-structured and worth knowing.


Not *always*.

The rule that makes sense to me is "code clearly". If it's a
choice between between being clear and being structured, being
clear wins. Usually you don't need to make the choice.

For purposes of clarity, I will always prefer:

while (yourChoiceForTrue) {
preamble;
if (doneExpression) goto done;
postamble;
}
done:

because the presence of "done:" alerts the reader to look for its
use. Without this flag the reader can easily miss the buried in
verbosity break in the original.

A clearer method may well be to combine doneExpression and
preamble in a separate routine and simplify the loop to:

while (preamble(preambleparams)) {
postamble;
}
 
M

Micah Cowan

Noah Roberts said:
Yeah, that was the point I was making. Some people like to
create a macro like that, I usually just use the actual loop when
I am testing code. I don't like to use forever loops in real
code but if I where to do so I might define something like that.

Yes, it is much better to use a condition to exit. Many times
people do something like the following:

while (always)
get input
if input is quit then die

do something
...

but it is much better do do something like this:

boolean quit = false /* or continue = true */

while (!quit)
get input
if input is quit then quit = true
else do something
...

"Much better"... IYO. I frequently prefer the former, and call it
a "mid-test" loop. IMO, mainstream programming languages have
syntax for a pretest loop and posttest loop, but no one supports
the midtest loop. So I use the former example above, which is the
closest thing available, rather than try to force it to be a
pretest loop.

Another way of forcing it to look like a pretest loop (but it
still isn't) is something like:

while ((c = getchar()) != EOF)
...


The second version is "structured" code whereas the first is not
(two exits).

Wrong. There is exactly one exit. It seems very structured to me,
if used properly: even if the syntax may not be as clean, it's
less ugly (to me) than going through loops to make it "proper".
Sometimes it is better to break structure, but it
always sacrifices maintainability and readability;

Not true. I frequently break structure for the explicit purpose
to improve portability. The typical case being something like:

int error_code = NO_ERROR;

a = malloc(sz_a);
if (a == NULL) { error_code = MEM_ERROR; goto my_end; }
(...calculations using a...)
b = malloc(sz_b);
if (b == NUL) { error_code = MEM_ERROR; goto cleanup_a; }
(...calculations using a and b...)
c = malloc(sz_c);
if (c == NUL) { error_code = MEM_ERROR; goto cleanup_b };
(...calculations using a, b and c...)

free (c);
cleanup_b:
free (b);
cleanup_a:
free (a);

my_end:
return error_code;

The alternatives include nesting a ton of if statements (which in
many cases can get cumbersome quickly), code repetition (always
something I strive to avoid; it usually leads to
bugs/inconsistencies), and checking some combination of a, b or c
before each and every operation involving them (ouch!!!). There's
also farming each block out to a separate function, which is
often what I try first, but sometimes this can be even more
cumbersome, especially if there are a lot of other variables
involved that would need to be passed around.
99.9999999% of the time it is not necissary to write unstructured
code and since it is a mistake to do so you shouldn't except for
that .000000001% of the time when you need to.

This percentage is somewhat exaggerated (to me). I've found it closer to
between 97-99% of the time, personally.

-Micah
 
M

Minti

Mike Wahler said:
Everyone knows that whitespace characters are weightless. :)

Oops sorry! I forgot we were talking about weights. I thought we were
talking about ................. never mind.
 
N

Noah Roberts

Chris said:
Noah Roberts wrote:




I'm sure that, being a well-structuring kind of chap, you just forgot
that `continue` is a C keyword ...

If you think that is funny:

-----Contents of funny.c (good name)----
boolean quit = false /* or continue = true */

while (!quit)
get input
if input is quit then quit = true
else do something
....
-----end contents----

----attempt compile----
jik-@darkstar:~$ gcc -pedantic funny.c
funny.c:1: error: parse error before "quit"
funny.c:3: error: `false' undeclared here (not in a function)
funny.c:3: error: parse error before "while"
-----end attempt----

Unfortunately it quit even trying at that point. It might have been
more entertaining had it continued. Putting it inside of a main loop is
even less entertaining because it stops trying to process the file much
sooner.

What an odd thing to focus on, yet several responders did.
The second one is horrid. The artifical boolean variable obscures what's
going on.

How so? It says "loop until I am told to quit" instead of "loop
forever". In my opinion "while (true)" is the lie because true never
stops being true yet you exit at some point.

Also you are assuming that quit is set to false within the loop, as it
is in the /pseudo/ code I wrote. This is only the case for very simple
programs or problems. More often your stop switch will be turned on
somewhere in a function you call in your loop, maybe several levels in.
If you want to exit the program at this point then you can call a
function that kills your process and never have to exit your forever
loop. Otherwise the best way is to use a stop switch use it to exit
your loop.

For simple problems the break or return method is acceptable but doesn't
hold up when things get much more complex.
Not *always*.

The rule that makes sense to me is "code clearly". If it's a choice
between between being clear and being structured, being clear wins.

I agree. I don't like "loop forever" but I do do things like this:

while test_case
if exception break
continue processing
end

I try to stay away from those though as it can really bite you in the
ass, and I only ever use forever loops in tests, never in production code.

NR
 
N

Noah Roberts

Micah said:
Not true. I frequently break structure for the explicit purpose
to improve portability. The typical case being something like:

int error_code = NO_ERROR;

a = malloc(sz_a);
if (a == NULL) { error_code = MEM_ERROR; goto my_end; }
(...calculations using a...)
b = malloc(sz_b);
if (b == NUL) { error_code = MEM_ERROR; goto cleanup_a; }
(...calculations using a and b...)
c = malloc(sz_c);
if (c == NUL) { error_code = MEM_ERROR; goto cleanup_b };
(...calculations using a, b and c...)

free (c);
cleanup_b:
free (b);
cleanup_a:
free (a);

my_end:
return error_code;

I think the above code is a pretty good representation of why I think
doing such things is a bad idea. That is just gross, but of course that
is my opinion.
The alternatives include nesting a ton of if statements (which in
many cases can get cumbersome quickly), code repetition (always
something I strive to avoid; it usually leads to
bugs/inconsistencies), and checking some combination of a, b or c
before each and every operation involving them (ouch!!!). There's
also farming each block out to a separate function, which is
often what I try first, but sometimes this can be even more
cumbersome, especially if there are a lot of other variables
involved that would need to be passed around.

How about this ;)

malloc(a...)
malloc(b...)
malloc(c...)

if (a && b && c) // or probably more readable to compare to null
explicetly...
do calcs...
else
clean up the mess // ie...if a free a, if b free b ...

In normal situations you will not find any major gain from doing it your
way, and I especially prefer mine in this case. In some abnormal
situation you may find you will gain performance enough to warrant all
that goto spagetti (my opinion) or even less often my way is impossible
if the allocations somehow depend on each other. A few extra tests is
not worth it IMHO and I think you have just as many jumps so the
performance gain depends only on the allocations not done.

Perhaps some other situation besides allocating memory would lead to
requiring something as ugly as the above. I would hope to never find
such a situation and would try very hard to find some other solution.
In fact I would probably prefer the nesting ifs myself.

But like I said, the verified null move algorithm involves the use of a
single goto statement and it is just the best and most readable way to
go about the problem. That is one rare case.

NR
 
C

Chris Dollin

Noah said:
Chris Dollin wrote:

If you think that is funny:

Amusing. Not funny. An aside.
What an odd thing to focus on, yet several responders did.

Of course. Nitpickery isn't offswitchable.
How so? It says "loop until I am told to quit" instead of "loop
forever". In my opinion "while (true)" is the lie because true never
stops being true yet you exit at some point.

`while(true)` is the signal that says "less common loop structure
here". Using a quit variable says "there's some boolean you have to
track through this code to look for assignments and check their
value". With `while (true)` you know it's breaks you have to look
for, which you knew anyway.

`lie` doesn't come into it.
Also you are assuming that quit is set to false within the loop, as it
is in the /pseudo/ code I wrote. This is only the case for very simple
programs or problems. More often your stop switch will be turned on
somewhere in a function you call in your loop, maybe several levels in.

That has happened to me maybe twice in twenty years.
For simple problems the break or return method is acceptable but doesn't
hold up when things get much more complex.

Maybe I don't write complex enough code.
I try to stay away from those though as it can really bite you in the
ass, and I only ever use forever loops in tests, never in production code.

Tests *are* production code :)
 
M

Micah Cowan

Noah Roberts said:
I think the above code is a pretty good representation of why I
think doing such things is a bad idea. That is just gross, but
of course that is my opinion.

How about this ;)

malloc(a...)
malloc(b...)
malloc(c...)

if (a && b && c) // or probably more readable to compare to null
explicetly...
do calcs...
else
clean up the mess // ie...if a free a, if b free b ...

That's all well and good: but what if you needed to use a before
you had the details on exactly what size you needed b to be?
In normal situations you will not find any major gain from doing
it your way, and I especially prefer mine in this case.

When yours is possible, so would I. Frequently it is not. And
these situations are *quite* normal. There are many programming
shops which consider examples such as the above to be the one
exception to the goto rule (though many more would have you never
use goto at all). I have no "goto" rule, only "readability" and
"no code repetition" rules and the like. Most of the time, they
eliminate the use of gotos, but in those cases when the use of
goto will improve readability and reduce redundant code, I will
not hesitate to use it.
Perhaps some other situation besides allocating memory would lead
to requiring something as ugly as the above. I would hope to
never find such a situation and would try very hard to find some
other solution. In fact I would probably prefer the nesting ifs
myself.

Ugh.... that's awful. What do you find ugly about the above? It's
simple and elegant, and you know where to find everything. The
nested ifs feels like wading through muck, to me.

-Micah
 
J

John Bode

[snip]
Not true. I frequently break structure for the explicit purpose
to improve portability. The typical case being something like:

int error_code = NO_ERROR;

a = malloc(sz_a);
if (a == NULL) { error_code = MEM_ERROR; goto my_end; }
(...calculations using a...)
b = malloc(sz_b);
if (b == NUL) { error_code = MEM_ERROR; goto cleanup_a; }
(...calculations using a and b...)
c = malloc(sz_c);
if (c == NUL) { error_code = MEM_ERROR; goto cleanup_b };
(...calculations using a, b and c...)

free (c);
cleanup_b:
free (b);
cleanup_a:
free (a);

my_end:
return error_code;

I'm not sure exactly how that improves portability?

My problem with this structure is that it does not clearly convey that
c is dependent on b and a, and that b is dependent on a. I would
rather have that relationship visually reinforced by nesting even if
it means marching halfway across the page, because then I can see the
relationship and its extent at a glance, instead of groveling through
the source.
 
S

Sheldon Simms

[snip]
Not true. I frequently break structure for the explicit purpose
to improve portability. The typical case being something like:

int error_code = NO_ERROR;

a = malloc(sz_a);
if (a == NULL) { error_code = MEM_ERROR; goto my_end; }
(...calculations using a...)
b = malloc(sz_b);
if (b == NUL) { error_code = MEM_ERROR; goto cleanup_a; }
(...calculations using a and b...)
c = malloc(sz_c);
if (c == NUL) { error_code = MEM_ERROR; goto cleanup_b };
(...calculations using a, b and c...)

free (c);
cleanup_b:
free (b);
cleanup_a:
free (a);

my_end:
return error_code;

My problem with this structure is that it does not clearly convey that
c is dependent on b and a, and that b is dependent on a. I would
rather have that relationship visually reinforced by nesting ...

What if these nested dependencies don't exist? Suppose the code is

int foo (FILE * f)
{
int error_code = NO_ERROR;

atype * a = NULL;
btype * b = NULL;
ctype * c = NULL;

a = malloc(sz_a);
if (a == NULL) goto mem_error;
if (fread(a, sizeof *a, 1, f) < 1) goto file_error;

b = malloc(sz_b);
if (b == NULL) goto cleanup_a;
if (fread(b, sizeof *b, 1, f) < 1) goto file_error;

c = malloc(sz_c);
if (c == NULL) goto cleanup_ab;
if (fread(c, sizeof *c, 1, f) < 1) goto file_error;

/* calculations using a, b and c */

goto cleanup_and_return;

mem_error:
error_code = MEM_ERROR;
goto cleanup_and_return;

file_error:
error_code = FILE_ERROR;
goto cleanup_and_return;

cleanup_and_return:
free(c);
free(b);
free(a);
return error_code;
}

I have written code like this before because I find it much
easier to sort out than the alternative. The least confusing
code is straight-line code. The most confusing is spaghetti code.
The reason goto was 'considered harmful' is because it enables
spaghetti code, not because the function is performs is itself
undesirable. In the example above, the control flow is very close
to straight-line: all gotos branch in one direction, and the
code reads from top to bottom. Moreover, the error handling has
all been banished to it's own segment of code and doesn't clutter
up the main logic of the function. Finally, the main part of the
function (the elided 'calculations') are at the top level of
the function instead of being buried in a huge pile of nested
braces.

-Sheldon

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&[email protected]
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&[email protected]
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&[email protected]
http://groups.google.com/groups?hl=...&oe=UTF-8&safe=off&selm=3253%40brl-smoke.ARPA
 

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
474,083
Messages
2,570,591
Members
47,212
Latest member
RobynWiley

Latest Threads

Top