While(1) or for(;;) for infinite loops?

E

Eric Sosman

All within a single project or source tree? I suggest that the
problem here is really that there needs to be a single
well-defined coding style for a given project.

There was a vogue some years ago for a practice called
"egoless programming." Had a good deal going for it, but
foundered on the scarcity of "egoless programmers" ...

Someone who's enough of a diplomat to get a large group
of skilled programmers to agree on "a single well-defined
coding style" and to stick to that style over a period of
years and through multiple personnel changes is wasting his
talents if he uses them for mere software. Let him instead
persuade North Korea and Iran to discontinue their nuclear
weapons programs; should be a piece of cake, comparatively.
 
B

Ben Pfaff

Eric Sosman said:
Someone who's enough of a diplomat to get a large group
of skilled programmers to agree on "a single well-defined
coding style" and to stick to that style over a period of
years and through multiple personnel changes is wasting his
talents if he uses them for mere software. Let him instead
persuade North Korea and Iran to discontinue their nuclear
weapons programs; should be a piece of cake, comparatively.

I don't see this problem in the projects that I work on, in my
experience. At companies, someone decrees the coding style, and
it gets enforced via code reviews. In the free software projects
that I work on, it's much the same. Even on very large projects
such as the Linux kernel, the coding style is more or less
followed.
 
E

Eric Sosman

I don't see this problem in the projects that I work on, in my
experience. At companies, someone decrees the coding style, and
it gets enforced via code reviews. In the free software projects
that I work on, it's much the same. Even on very large projects
such as the Linux kernel, the coding style is more or less
followed.

Our experiences differ, and I guess you've been more
fortunate than I in finding organizations that take niceties
like "coding style" and "code reviews" seriously.

The largest source tree I ever worked with extensively
was about three million lines, had a history about fifteen
years long, had been worked on by maybe a hundred or hundred
fifty programmers, and was a Gawdawful mess. But the company
had a "cowboy programmer" culture, so what would one expect?

Another source tree I touched lightly was the product of
a highly-organized, button-down Big Company, where all the
Software Engineering Methodologies were duly observed as they
came in and out of fashion. The source was about twenty-five
million lines, had a history stretching back some twenty-five
years, had been worked on by several hundred programmers --
and was still a Gawdawful mess despite all the methodology.

Seems to me that "Gawdawful mess" is the norm ...
 
B

Ben Pfaff

Eric Sosman said:
Our experiences differ, and I guess you've been more
fortunate than I in finding organizations that take niceties
like "coding style" and "code reviews" seriously. [...stories...]
Seems to me that "Gawdawful mess" is the norm ...

I might as well relate my own experiences. I won't bother with
the free software projects, since the source code is all out
there for everyone to look at. I've only had two commercial
coding stints worth talking about, so I'll talk about those.

From 2003 to 2007 I worked at a very large x86 virtualization
software vendor. Their tree was, if I recall correctly, on the
order of a million lines of code, with history stretching back to
approximately 1998. The founder had decreed a particular (rather
odd) coding style, and the whole tree followed it with rare
exceptions. Attempts to add code that violated it were stomped
out in code review.

In 2007 I was a founding employee at my current company. I
decreed a coding style, and it has been followed pretty well
since then, at least in the projects in which I participate.
Again, violations are stomped out in code review.

I am probably generalizing from too few data points.
 
J

James Dow Allen

.
  If someone loses semicolons, he might not be the right
  person to review C code.

I don't think Kenneth was concerned to cope with *incompetent*
programmers; he just wanted to save them a few seconds' worth
of concentration by using a standard easy-to-read style.

As others point out, adding "{ ... }" even where unneeded
is often good, especially since you'll often need to add
them later anyway. This leads to a strong argument for
a particular brace-placement style:

Using "while ... if ... else ... else ..." as example, fully
adding the "{ ... }" wastes 8 lines vertically if you always
place braces on their own line, but only 2 lines using
True Style(tm).

James Dow Allen
 
P

Phil Carmody

Keith Thompson said:
I rarely see or use do-while loops in C. (I think the last time I
used one was in my IOCCC entry;

There's your mistake - you should have used recursion instead!
Then again, that doesn't always work either.

Phil
 
N

Nick Keighley

I don't see this problem in the projects that I work on, in my
experience.  At companies, someone decrees the coding style, and
it gets enforced via code reviews.  

I've seen it enforced by the check-in system. You code got indented
and diffed before it was checked in. The checkin failed if diffs found
a difference. You *could* override it but then it sent an email to the
Configuration Controller...
 
E

Eric Sosman

[...]
I don't see this problem in the projects that I work on, in my
experience. At companies, someone decrees the coding style, and
it gets enforced via code reviews.

I've seen it enforced by the check-in system. You code got indented
and diffed before it was checked in. The checkin failed if diffs found
a difference. You *could* override it but then it sent an email to the
Configuration Controller...

<topicality level="marginal">

IMHO, that's a terrible way to do things. By insisting on
a "canonical" arrangement of white space, it forbids the use of
white space as a medium of expression to aid readability. Two
situations seem to crop up fairly often:

First, when a long expression is broken across multiple lines
it can be helpful to indent the continuations so as to reflect the
logical structure of the expression. Here's an actual example
(albeit from a "just for fun" program):

if (SQUARE(p->crtx - ball[k].crtx)
+ SQUARE(p->crty - ball[k].crty)
<= SQUARE(p->crtr + ball[k].crtr))

A style that insisted (as some do) "continuations are uniformly
indented N spaces deeper than the continued line" would, IMHO,
disimprove the readability.

Second, it is not uncommon to display tabular information
in comments, where the horizontal position of each comment is
related not only to that of the line's "payload," but also to
the positions of comments on nearby lines. Another example
(from another toy program, adapted from code by Paul Hsieh):

/* If it's a straight, then ranks = ...0111110... */
unsigned int temp = ranks ^ (ranks - 1); /* temp = ...0000011... */
temp = (temp + 1) >> 1; /* temp = ...0000010... */
temp = (temp << 5) - temp; /* temp = ...0111110... */

Again, a style that insisted "on-the-line comments begin in column
N (or N' spaces after the payload)" would destroy the arrangement,
depriving the reader of useful information or at the very least
making him work harder to extract it.

We build computers to be our servants, not our masters. When
we let an "indent" program rearrange code and disrupt the meaning
that it's too stupid to comprehend, we've surrendered to our own
tools, we have chosen not to think.

See also "With Folded Hands" by Jack Williamson.

</topicality>
 
S

Stefan Ram

Eric Sosman said:
if (SQUARE(p->crtx - ball[k].crtx)
+ SQUARE(p->crty - ball[k].crty)
<= SQUARE(p->crtr + ball[k].crtr))
A style that insisted (as some do) "continuations are uniformly
indented N spaces deeper than the continued line" would, IMHO,
disimprove the readability.

I am using a uniform indentation of »2 spaces deeper«,
but only based on brackets, parentheses, braces and so. Thus,

if
( SQUARE( p->crtx - ball[ k ].crtx )+
SQUARE( p->crty - ball[ k ].crty )<=
SQUARE( p->crtr + ball[ k ].crtr ))

This looks readable to me. My rationale:

One Way to Format Parentheses

There are several different ways to format texts with braces
and parentheses. One of them is being described here.

Indentation within Braces

An indentation of just one space often is too small to be seen
clearly, because the natural width and form of characters
often varies by an amount that is not very much smaller than a
space. Therefore, the indentation should amount to at least
two positions. In order not to waste horizontal spaces, an
indentation of exactly two positions is chosen. This means,
that the left position of the next level is two larger than
the position of the directly enclosing level.

Indentation by two positions within a block

{ ++x;
++x; }
^ ^
0 2

Bad: A small indentation by one position is not always visible
clearly

{++x;
++x; }

Good: The indentation by two positions is visible clearly

{ ++x;
++x; }

Bad: A large indentation by more than two positions wastes
horizontal space with no additional benefit

{ ++x;
++x; }

Spaces within braces

In mathematics, there are often no spaces at the inner side of
parentheses or braces in expressions, but spaces are used
indeed at the inner side of braces in set notation, when the
braces contain a description (not when they contain a list).

Spaces in set notation

{ x | x > 2 }

This style is adopted here: One space is written at the inner
side of braces.

Spaces at the inner side of parentheses within a block

{ ++x; }

This style is consistent with the indentation by two
positions, because only using this style, corresponding parts
of two lines have the same position.

Bad: No space after the first brace, the two statements are
misaligned

{++x;
++x; }

Good: One space after the first brace, the two statements are
properly aligned

{ ++x;
++x; }

Bad: Two spaces after the first brace, the two statements are
misaligned

{ ++x;
++x; }

There are some exceptions to this rule: No spaces are used
within empty braces "{}" and between two or more closing
braces of the same direction "}}", except, when the first one
of them is part of an empty pair "{} }" (an empty pair of
braces if treated like a single non-braces character).

Unified rules for all Brackets

For simplicity and uniformity, the rules from above apply to
all kinds of brackets, including parentheses, braces (curly
brackets), square brackets, and angle brackets.

Spaces within parentheses and square brackets

{ y = f( x )+ g() + a[ 2 ]; }

Binary operators are sorrounded by a space, but the space is
omitted, when there already is a space on the other side of a
sequence of brackets directly beside the operator: By this rule,
" )+" is written instead of " ) +".

Representation of the Syntactical Structure

A method declaration in Java consists of a head and a body.
The following representation shows this structure:

Good formatting according to the structure

void alpha() // head
{ beta(); } // body

The following formatting is misleading, because the line break
does not match the structural break:

Bad line break within the body

void alpha() { // head and the beginning of the body
beta(); } // the rest of the body

This formatting also would make no sense for blocks within
blocks. So it is often not used for such blocks. Therefore
even the adopters of this style can not use it uniformly.

Opening Braces Look Like "bullets"

There is a well known style to publish lists in typography
using bullets sticking out on the left, looking like this:

Common list representation with bullets in typography

o This is the first point
of this list, it is written
here just as an example.

o Here is another entry

o This is another example given
just as an example to show
an example

The braces of the beginnings of blocks stand out on the left
just the same, when the formatting being described here is
used, so they look quite naturally as beginning-of-a-block
markers, when one is used to the typographical list notation:

Left braces look like bullets to mark blocks

{ printf(); printf();
printf(); printf(); printf();
printf(); printf(); }

{ printf(); printf(); }

{ printf(); printf(); printf();
printf(); printf();
printf(); }

Neutrality

Someone wrote this C code:

while( fgets( eingabe, sizeof eingabe, stdin ))
if( sscanf( eingabe, "%d", &wert )!= 1 )
fprintf( stderr, "Please enter a number!\n" );
else
summe += wert;

It amazes me that I can add braces by my style conventions
(not changing the meaning of the code)
without the need to change the position of any character of
the given code or need to change the overall number of lines:

The code from above plus braces

while( fgets( eingabe, sizeof eingabe, stdin ))
{ if( sscanf( eingabe, "%d", &wert )!= 1 )
{ fprintf( stderr, "Please enter a number!\n" ); }
else
{ summe += wert; }}

Insofar, my bracing style might be considered non-obtrusive.

Lines per Contents

Lines containing only a single brace waste vertical space, so
less contents fits on the same screen space. Therefore, I usually
avoid them, but sometimes I do use them, when this helps to
increase readability. I also might temporarily use them when editing
a section of code. Of course, they would help programmers paid or
being judged by the lines-of-code productivity.
 
W

Willem

Richard wrote:
) But I would bracket it thus
)
) ,----
)| if ((SQUARE(p->crtx - ball[k].crtx)
)| + SQUARE(p->crty - ball[k].crty))
)| <= SQUARE(p->crtr + ball[k].crtr))
) `----
) There is no room for confusion

Agreed with the bracketing. However, I'd add a bit of internal whitespace:

| if ( ( SQUARE(p->crtx - ball[k].crtx)
| + SQUARE(p->crty - ball[k].crty))
| <= SQUARE(p->crtr + ball[k].crtr))

so that it visually stands out what is grouped with what.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
W

Willem

Richard wrote:
)
)> Richard wrote:
)> ) But I would bracket it thus
)> )
)> ) ,----
)> )| if ((SQUARE(p->crtx - ball[k].crtx)
)> )| + SQUARE(p->crty - ball[k].crty))
)> )| <= SQUARE(p->crtr + ball[k].crtr))
)> ) `----
)> ) There is no room for confusion
)>
)> Agreed with the bracketing. However, I'd add a bit of internal whitespace:
)>
)> | if ( ( SQUARE(p->crtx - ball[k].crtx)
)> | + SQUARE(p->crty - ball[k].crty))
)> | <= SQUARE(p->crtr + ball[k].crtr))
)>
)> so that it visually stands out what is grouped with what.
)>
)> SaSW, Willem
)
) There shouldn't be any need. Extraneous whitespace on the same line
) inside part of an expression sucks most times. Brackets and a bracket
) aware editor sorts that out. I find your version less readable. The
) double brackets by the if and before the "<=" show you all you need to
) know IMO. I would also remove the white space around "-" too btw.

Why does adding whitespace make something *less* readable ?

All I can read from your arguments is that the brackets are 'good enough',
you don't seem to be mentioning one single reason why the extra whitespace
makes it *less* readable. Nor do I see any argument refuting my point that
the elements stand out visually in this arrangement.



SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Kenneth said:
Kaz Kylheku wrote:
[...]
I think that I always add braces in a do/while, even if there is just a
single expression. It's easy to see why you might forget you can have a
single statement there.
[...]

I, too, "usually" use braces on 1-line for/while/whatever loops. What I
can say I "always" do is put the body on a line apart from the control
line.

I think most people here would agree that this style just "looks wrong":

for ( foo ; bar ; baz );
or
while ( do_something() );

That lone semicolon is too easily "lost" by the person reading the code.

The other time I "always" do something is put braces around a multi-line,
single compound statement, body. For example, I would not use this syntax
which I have found in numerous places throughout code I maintain:

for ( foo ; bar ; baz )
if ( something )
do_this();
else
do_that();

Or, worse, nested if/else without braces:

if ( this )
if ( that )
do_something();
else if ( another )
do_another();
else
do_yet_another();
else
something_else();

Of course, due to multiple platforms with multiple editors which have
multiple tab-stop settings, it rarely looks so nicely indented. It can
take several minutes "fixing" it, making sure to carefully put the braces
so as
to not change the meaning. (Not as simple as it looks when not all "if"s
have an "else".)

I always use compound statements as the bodies of control statements (if
else for do while switch try catch).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAksjr5gACgkQG6NzcAXitM8+4QCfWmOSwlcPw5L2Hlx269kHzjkq
pHsAn0UgI+bUp7Di/IbJ2lIUPXcVo/AQ
=1q7B
-----END PGP SIGNATURE-----
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Peter said:
Macros are not C?

Macros are part of C but it is completely different from C.
C is a programming language but the preprocessing language is a text
replacement language.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAksjsQcACgkQG6NzcAXitM8Z1gCdHQ3HhqI4sz8056VgSfjEI01s
jrsAoJJ0A9HlJ11gyvSpWVuL1hm0KMS3
=yWKX
-----END PGP SIGNATURE-----
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Keith said:
In C90, the identifier "true" is undeclared unless you've defined
it yourself (or it's defined by some header you've #included).
In C99, it's undeclared unless you have "#include <stdbool.h>" or,
as in C90, you've defined it yourself (which could create a conflict
if you later add "#include <stdbool.h>").

I wouldn't hesitate to write "while (true)" if I've already caused
"true" to be defined for some other reason, but I wouldn't introduce
it just for that purpose, since "while (1)" is such a common and
well known idiom.

I write while(true) because I am a C++ programmer. When I need to write code
in C, I always #include <stdbool.h> when boolean logic is needed in the
program. Because, in C++, the condition of while is a bool so that I write
while(true) instead of while(1) or even worse for(;;) which is completely
nonsense for non-C programmers. (When I first seen for(;;), I think that the
loop doesn't run at all because the condition is null.)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAksjsjEACgkQG6NzcAXitM8WvACeI0pZxLyvE+0nc7Tfp67JU5jZ
23MAn0pW5K4do5JOWmNxzL9nCft6B//8
=tGsi
-----END PGP SIGNATURE-----
 
E

Eric Sosman

Macros are part of C but it is completely different from C.

As you've stated it, this is nonsense. But we think we
know what you mean, anyhow: The syntax and semantics of the
preprocessing parts of C are quite unlike those of the rest
of C.
C is a programming language but the preprocessing language is a text
replacement language.

Actually, it's a token replacement language (pedantically,
a preprocessing token replacement language). The difference
is occasionally important, as in

#define HELLO "Bonjour"
puts ("HELLO, WORLD!");

.... where the output is "HELLO, WORLD!" and not "Bonjour, WORLD!".
 
K

Keith Thompson

Michael Tsang said:
Keith Thompson wrote: [...]
I wouldn't hesitate to write "while (true)" if I've already caused
"true" to be defined for some other reason, but I wouldn't introduce
it just for that purpose, since "while (1)" is such a common and
well known idiom.

I write while(true) because I am a C++ programmer. When I need to
write code in C, I always #include <stdbool.h> when boolean logic is
needed in the program. Because, in C++, the condition of while is a
bool so that I write while(true) instead of while(1) or even worse
for(;;) which is completely nonsense for non-C programmers. (When I
first seen for(;;), I think that the loop doesn't run at all because
the condition is null.)

I find it useful to adopt the idioms of the language I'm working in.
C and C++ are two distinct (but deceptively similar) languages.

In C, the condition in a while statement is of scalar type, and
"while (1)" is a common idiom for an infinite loop. There's nothing
wrong with "while (true)"; after all, _Bool is a scalar type as well.
(Well, there's the additional requirement for "#include <stdbool.h>",
and the risk of needing to compile your code on an implementation
that doesn't support <stdbool.h>.)

Yes, "for(;;)" is complete nonsense for non-C programmers. So is
most of the language. Unless you have some specific reason to want
to make your code clear to non-C programmers, don't worry about it.

At the very least, however you write your own code, you need
to understand "while (1)" and "for (;;)" when you see it in
others' code.
 
K

Keith Thompson

pete said:
Being able to compile code which contains macros is a requirement
in order for any software to qualify as an implementation of C.

All of the rules for C macros are written in the C standard.

True.

Ok, let's put it this way. You can think of C as a combination of
two different languages. One is the language defined by the early
translation phases, typically referred to as the preprocessor.
The other is what's produced by the preprocessor and processed by
the remaining translation phases; you can think of this language as
what C would look like if the preprocessor were dropped. These two
languages are very different. I think that's what Michael was
trying to say, and it's a valid point.
 
C

Curtis Dyer

But it's not; it works in plenty of other languages. Admittedly,
I'm not sure if "for(;;)" is considered as idiomatic in other
languages as it is in C.

But C has had a tremendous impact over the years, so some of C is
also familiar to people who have used languages like Java, C++,
PHP, Perl, etc. I knew about certain C idioms before I ever read
or wrote a line of C. (I only started learning programming about
six years ago.)
Unless you have some specific reason
to want to make your code clear to non-C programmers, don't
worry about it.
It's impossible (or at least very difficult) to write C code
that doesn't use any C-isms.
However if people understand most of what is going on, they can
often fill the incomprehensible bits by context. [...]
However if everything is incomprehensible, however, then you
can't do this. So by systematically preferring if else to ?:,
not using logical short-circuits, using while(true), etc, you
can help people from a C-light background to read your code.

The ternary operator and short-circuit evaluation are definitely
not particular to C only. While I don't think you should use
these things just because they're there, I do feel that not making
the most of the tools you have hurts more than it helps.

Seeing as how I'm still a C newcomer, I prefer to read C that
makes good use of C idioms; it helps me learn the language better.
 
B

Billy Bong

Kaz Kylheku wrote:

[snip]
Often it is the case that one or more iterations of a body ensure that
something interesting which was not true previously is now true. We confirm it
to be false at the top as the condition for executing another iteration. Or we
confirm it to be true at the bottom, and do not execute another iteration.

And sometimes we confirm it to be false at the top and confirm it again
to be false *after* the bottom, as in this snippet of open source code
from a file named match.c:

while (consp(piter) && consp(viter))
{
bindings = dest_bind(bindings, car(piter), car(viter));
if (bindings == t)
return t;
piter = cdr(piter);
viter = cdr(viter);
} while (consp(piter) && consp(viter));

Most if not all compilers (including those typically invoked with the
"gcc" and "g++" commands) do not issue a warning for this code.
Fortunately, there is at least one "compiler" that does (on the second
while statement):

Info 722: Suspicious use of ;

The code most likely used to be a do loop that got converted to a while
loop but was not properly "maintained". And note the inconsistency in
the brace alignment with the rest of the code. If consistency trumps
religious beliefs, it should be the following for the first line:

while (consp(piter) && consp(viter)) {

It should be noted that the same "compiler" issues numerous other
warnings of potential concern on this open source code.

Regards
 

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,780
Messages
2,569,614
Members
45,289
Latest member
stfp04

Latest Threads

Top