while (1) vs. for ( ;; )

B

Baxter

Alan Balmer said:
On Wed, 31 Aug 2005 21:12:25 -0700, "Baxter"


You are unfamiliar with the term "infinite loop"?

And how many infinite loops should there be in your program?

Myself, I've got over a million lines of code I've written without any need
of an infinite loop. Some of the code I've inherited has them - but in
EVERY case, they have one or more exit conditions -- and thus _are_not_
actually infinite loops.

Sounds like some here are mis-using this kind of loop.
 
C

Charlie Gordon

Tim Rentsch said:
Fixing them might take as long as two or three minutes; so
to save you the trouble, here's a command for that:

sed 's:\(while[ ]*(\)[ ]*l[ ]*):\1 l /*** L, NOT 1! ***/ ):'

Please feel free to use either or both of these aids
to help identify or correct such egregious code.

Thank you professor, you are so grand!
You will note that this sed script will break code where the while(l) appears in
/* comments */
or change code behaviour if it appears in C strings.

Yes, that's a shortcoming. Do you expect such things to
actually occur, or is this just a silly objection for the
purpose of scoring debate points?

What do you think your attitude called for, patronizing me with scripting aids,
as if I couldn't figure how to search and replace when this was not even the
issue at all ?
In either case, both conditions are easily addressed.

1. In cases where 'while(l)' appears inside comments, the
new code will get an error message out of the compiler.
Use an editor and fix the problem. (Does anyone still
use comments rather than '#if 0' to comment out sections
of code?)

Java programmers don't have much of a choice, and they keep doing it when they
switch to C.
I hate this, but it does happen in real life, I see it every day.
Don't tell me this can be solved by preprocessing java code, that's indeed what
we do, but I cannot control the rest of the crowd.
2. In cases where 'while(l)' appears inside strings (or
character literals), these can be found easily using
diff and grep. Use an editor and fix them.

Had this been the issue, I would have easily searched and fixed them in the
general case, with a regex-file-query-replace.
Automation has its shortcomings. Honed tools are the answer.
When I wrote my earlier response, I assumed that there some
level of legitimate concern for an actual potential problem.
Now it appears that you are objecting solely for the purpose
of raising objections, and not because you have any interest
in solving a problem. If so, please do everyone a favor and
just go away.

Badly named variables are an actual problem.

This debate looked rather vain at first, but it seem to go a little bit beyond
simple style issues.
The objection I raised may seem futile to you, but it makes me want to see
neither while(1) not while(l) in any code my people will produce. This answers
the original question.

Chqrlie.
 
C

Charlie Gordon

Tim Rentsch said:
Wolfgang Riedel said:
grep -n 'while[ ]*([ ]*l[ ]*)'

to find them. (Add tabs next to the spaces inside brackets
<>snip

you didn't try said grep on any OS known to mankind, I guess.

In fact, I did. The command in the posting was copied
directly out of the shell script file that had the command
in it.

If you read the earlier posting again, you should see that
the point of the grep is to find while's that look like
'while(1)' but actually have a lowercase L, rather than 1,
as the control expression. The grep command above will do
that.

My point was not what you thought I meant:
When both while(1) and while(l) are used in a program, one can easily mistake
one for the other, if they can at all be distinguished in font used for display.
Because of this, I recomend to not use either construct. and not call variables
l.

Chqrlie.
 
C

Christian Bau

"Baxter said:
It's not your job to write to the machine or to the compiler. Your job is
to write to the next guy (probably yourself) who will be reading the code.

I expect the person who reads my C code to be able to understand C. I
don't care if she or he understands English.
 
C

Christian Bau

"Charlie Gordon said:
Yeh, that's an idea! let's get the worst of both worlds :

// To settle the while(1) / for(;;) debate, here is a compromise :

for (; 1 ;) { ... }

A "compromise" that combines the worst aspects of both styles...
 
A

Alan Balmer

And how many infinite loops should there be in your program?

Myself, I've got over a million lines of code I've written without any need
of an infinite loop. Some of the code I've inherited has them - but in
EVERY case, they have one or more exit conditions -- and thus _are_not_
actually infinite loops.

Sounds like some here are mis-using this kind of loop.
It's a language problem. You confuse English with programming
languages and programmers' jargon :)
 
C

Charlie Gordon

Christian Bau said:
A "compromise" that combines the worst aspects of both styles...

We can make these "infinite" loops "evil" too :

for (6;6;6) { ... }
 
R

Richard Heathfield

Default User said:
I "should" do what I feel comfortable with, not what usenet people want
me to do.

Brian, I think you forgot to read the small print. Check page 137829, para
19031.9.177.12.753(j), subsection 3 of your Usenet agreement.
 
D

Default User

Richard said:
Default User said:

Brian, I think you forgot to read the small print. Check page 137829,
para 19031.9.177.12.753(j), subsection 3 of your Usenet agreement.


Ah yes, the "High-Handed Law". I forgot about that.



Brian
 
T

Tim Rentsch

Flash Gordon said:
I don't consider the warning to be defective.

Note that "defective warnings" was intended by websnarf as
ironic. The original phrase was "errant warning message".
Being able to get a warning for loop control expressions
that are constant is perfectly ok; it is the message for
the particular case of 'while(1)' that is errant. The
followup by Keith Thompson articulates this nicely.

You can have conditions
which always evaluate to true or false for a number of reasons:

1) It will evaluate to a different value on some other implementation
leading to different behaviour and this is correct.
Why not use #if to select the appropriate behaviour so that it is
obvious that it never changes for a given build?

First, this approach applies to if's rather than while/for,
so it's not really germane to the topic under discussion,
which is warnings for 'while' control expressions that
are constant.

Second, using '#if' when 'if' can be used instead seems like
a step backwards. One nice thing about writing code with
'if' rather than '#if' is that the code in the conditional
always gets compiled (and so must compile correctly). Also,
consider something like:

if( DEFINED_1_OR_0 ) ...
else if( x > y ) ...
else ...

This code fragment can be rewritten using #if, but the form
of the result suffers.

As a development practice I always recommend using #if only
for sections of code that simply won't compile on other
platforms. There are of course some cases where it's better
to make an exception, but by and large code that uses 'if'
rather than '#if' tends to be more reliable and easier to
work on.

2) You are doing an "infinite" loop (it might break out from the middle)
and the for (;;) idiom can be used in this instance.

This statement presumes that there is never any reason to
prefer 'while(1)' to 'for(;;)', so the reasoning here is
rather circular. Contrary to the presumption, several
different reasons have been given for preferring the
'while(1)' form.

3) You've made an error (maybe due to mixing signed and unsigned or
something) and the condition should *not* always evaluate to the same
value.

Sure, but that doesn't have to do with looping necessarily.
The -W flag in gcc will generate warnings for expressions
like 'x >= 0' if x is unsigned. The concern is that the
expression is unexpectedly constant. The '1' in 'while(1)'
is constant, but it is not *unexpectely* constant.

[various comments that Flash prefers using 'for'
for infinite looping, and getting warnings for
any constant "conditional expression"]

For me while(1) is not more intuitive than for (;;). I'm not disputing
it is for you, just pointing out that for some of us there is not the
down side you have.

Yes, I understood that. I'm not advocating that anyone stop
using 'for(;;)'. However, I think it's a mistake to make a
choice of this kind just because there's some warning
message that flags one form or the other. You wouldn't stop
using 'for(;;)' just because some compiler decided to issue
a warning message for it, would you? Yet from my point of
view such a warning message has a (small) positive value (as
long as it can be turned off).

I definitely agree here. Both while(1) and for(;;) are perfectly clear
if you no C, and I can see no instance where you would want to change
all instances of FOREVER to something other than an infinite loop, so it
adds something non-standard to be learned (you have to learn to always
use it) with no significant benefit that I can see.

Note that I wasn't advocating that 'FOREVER' be used; only
that I wouldn't have a problem with it if the team decided
that it should be used.

As for benefits, there are at least three potential benefits:

1. It stands out. It's nice to be able to pick out easily
the places infinite loops appear, especially if you
believe that infinite loops usually should be recast
so that they are not infinite. (The "infinite" here
really means "apparently infinite"; most "infinite"
loops have break's or return's that stop them from
being actual infinite loops.)

2. There can be benefit to being able to change what
happens during infinite looping, as noted in other
messages in this tree. You should be able to find
these if you use google groups and search for
'LOOPTRACK'.

3. If there is team consensus that 'FOREVER' should be
used, that itself is a benefit; having a team be
more unified provides positive value.

Whether these benefits are worth the costs naturally
depends on what the costs are judged to be.
 
R

Richard Heathfield

Thad Smith said:
Kevin Handy wrote:


Is the following always portable?

#include <stdio.h>
int main(void) {
int a;
if (a | !a) printf ("Always\n");
return 0;
}

In a curious way, it is! There is at least one guarantee that we have about
this program's behaviour under any conforming implementation. Kudos to
non-regulars who spot which guarantee I'm talking about.
 
B

Barry Schwarz

snip
Is the following always portable?

#include <stdio.h>
int main(void) {
int a;
if (a | !a) printf ("Always\n");
return 0;
}
Precisely the opposite.


<<Remove the del for email>>
 
T

Thad Smith

Kevin said:
Chris McDonald wrote:

Why not use

while(is_the_pope_catholic) {

Challenge your reader:
while (2+2 == 4) or
while (1+1+1 == 6/2) or
while (24+7 == 24|7) or
???

They should evaluate to a suitable constant.

Is the following always portable?

#include <stdio.h>
int main(void) {
int a;
if (a | !a) printf ("Always\n");
return 0;
}


Thad
 
D

Dave Thompson

<OT>
COBOL doesn't have multiple entry points into functions. Functions
in COBOL are a fairly restrictive language feature. I suspect you're
thinking of "programs", which is what COBOL calls the things that are
closest to what C calls "functions", or what are sometimes called
"subroutines".
Actually it calls them 'program-units'. I don't believe 'program' is
officially defined but is generally taken to be a collection, usually
link-edited, of progam-units, which officially is a 'run-unit'.
Fortran and Ada similarly have 'subprogram's linked into a program.
Standard COBOL does not permit multiple entry points in programs, but
it's an extension in several popular implementations.
</OT>
FWIW, (standard) Fortran does. And (no surprise) PL/I. But IIRC PL/I
does not allow the parameter/formal list to vary, as Fortran does,
which (latter) provides great opportunity for error both in
implementation and in usage.
Multiple entry points would certainly be *a* way of implementing the
design Richard describes, but I don't see much justification for
using them that way. Just using two functions would be clearer and
less error-prone, I suspect. And it strikes me as unlikely that,
conversely, this design would be used to argue for allowing multiple
entry points in a language.
Agree there.
I must admit, though, that I'm not fond of Richard's scheme in most
cases; unless a function is time-critical or the checks are very
expensive I don't see the advantage to skipping the checks. That
shifts the burden of validation from the program to the programmer.

AIUI Eiffel requires (well, strongly encourages) you to designate
preconditions for routines (OOishly called 'features') which it
promotes to callers, and may then be able to optimize away.

- David.Thompson1 at worldnet.att.net
 
T

Thad Smith

Flash said:
I don't consider the warning to be defective. You can have conditions
which always evaluate to true or false for a number of reasons:

1) It will evaluate to a different value on some other implementation
leading to different behaviour and this is correct.
Why not use #if to select the appropriate behaviour so that it is
obvious that it never changes for a given build?

The expression is less messy without the separate #if / #endif lines.

I encountered a situation today with (the equivalent of)

sysparams.h
#define MIN_AREA_ADDR 0x00 /* minimum allowed EE write address */
#define MAX_AREA_ADDR 0x3f /* maximum allowed EE write address */

code.c:
#include "sysparams.h>
unsigned char addr;
...
addr = get_addr();
if (addr >= MIN_AREA_ADDR && addr <= MAX_AREA_ADDR) {
write_eeprom (addr, data);
}

The compiler issued a warning that addr >= MIN_AREA_ADDR was always
true. With this particular value, it was, but I would rather not get
the warning. I could do something like

if (
#if MIN_AREA_ADDR > 0
addr >= MIN_AREA_ADDR &&
#endif
addr <= MAX_AREA_ADDR) {

but that seems messy.

The ideal situation, for me, would be something like

#define NOWARN(x) _Pragma("-warning") x _Pragma(".warning")
...
if (NOWARN(addr >= MIN_AREA_ADDR) && addr <= MAX_AREA_ADDR) {

That's still messy, but I would rather add a little mess to suppress the
expected warning in known locations, but still look for the error in
unexpected places.

Thad
 
C

Christian Bau

Thad Smith said:
The expression is less messy without the separate #if / #endif lines.

I encountered a situation today with (the equivalent of)

sysparams.h
#define MIN_AREA_ADDR 0x00 /* minimum allowed EE write address */
#define MAX_AREA_ADDR 0x3f /* maximum allowed EE write address */

code.c:
#include "sysparams.h>
unsigned char addr;
...
addr = get_addr();
if (addr >= MIN_AREA_ADDR && addr <= MAX_AREA_ADDR) {
write_eeprom (addr, data);
}

The compiler issued a warning that addr >= MIN_AREA_ADDR was always
true. With this particular value, it was, but I would rather not get
the warning. I could do something like

if (
#if MIN_AREA_ADDR > 0
addr >= MIN_AREA_ADDR &&
#endif
addr <= MAX_AREA_ADDR) {

but that seems messy.

In similar situations, I have written

if ((unsigned int) (addr - MIN_AREA_ADDR) <=
(unsigned int) (MAX_AREA_ADDR - MIN_AREA_ADDR))

with a suitable comment why such stupid code would be required. I can
feel your pain.

A heuristics to be used in a good compiler that picks this case and
avoids the warning is not too difficult: The warning is there because
with a value of addr == MIN_AREA_ADDR - 1 the test "addr >=
MIN_AREA_ADDR" would be unexpectedly true instead of false (potential
bug). However, the complete test "addr >= MIN_AREA_ADDR && addr <=
MAX_AREA_ADDR" would still give the expected result!
 
B

Baxter

Alan Balmer said:
It's a language problem. You confuse English with programming
languages and programmers' jargon :)

I don't confuse anything - because I write in English and not in
computerese.
 
S

Steven Kobes

Quoting Thad Smith:
Is the following always portable?

#include <stdio.h>
int main(void) {
int a;
if (a | !a) printf ("Always\n");
return 0;
}

Quoting Richard Heathfield:
In a curious way, it is! There is at least one guarantee that we
have about this program's behaviour under any conforming
implementation. Kudos to non-regulars who spot which guarantee I'm
talking about.

I give up... what guarantee are you talking about?
 
B

Barry Schwarz

Quoting Thad Smith:

Quoting Richard Heathfield:

I give up... what guarantee are you talking about?

It's been a couple of days so here is a hint. Think of the most
common types of undefined behavior. I think this is in the top five,
probably #1 or #2. Some compilers even generate a diagnostic for
this.


<<Remove the del for email>>
 
A

Alexei A. Frounze

Barry Schwarz said:
It's been a couple of days so here is a hint. Think of the most
common types of undefined behavior. I think this is in the top five,
probably #1 or #2. Some compilers even generate a diagnostic for
this.

IMO, the above may be warned as use of uninitialized variable.
And the actual problem maybe the mighty trap taking on trap representation
of uninitialized int.
If it wasn't for the last one, there would be no reason to warn at all on
either (a | !a) or (a & !a), because both would always evaluate to constant,
no matter what the (valid) values of a are...

Alex
 

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,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top