[comp.lang.c] Always use braces

bill@twwells.uucp (T. William Wells) (12/23/88)

In article <8@estinc.UUCP> fnf@estinc.UUCP (Fred Fish) writes:
: Since this is my pet peeve #1 about C style, I couldn't resist.  There
: is no ambiguity if you simply make it a habit to ALWAYS include braces
: for {if, while, do, for} etc, even when they are not strictly necessary.

Absolutely. One should always include optional braces.  There are two
advantages:

    1) A decrease in the likelyhood of programming errors.

    2) An increase in the readability of the program.

One should also never write a compound statement on the same line as
the head of the statement it is embedded in. E.g., instead of:

	for (a; b; c) statement;

one should write:

	for (a; b; c) {
		statement;
	}

Doing that makes finding the statement quite a bit easier.

: I was recently helping out a freshman CS major with her C homework and
: found out, to my horror, that the teacher in the course was marking
: off points for code which included braces when they weren't strictly
: required.  They were teaching her to write code like:
:
:       inchar = getchar ();
:       while (inchar != EOF)
:               if (inchar == 0)
:                       goto done;
:               else
:                       inchar = getchar ();
: done: return inchar;
:
: Ickkk!!!

Double Ickkkk!!!! A goto where a break would have done.

---
Bill
{uunet|novavax}!proxftl!twwells!bill

cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) (12/24/88)

In article <271@twwells.uucp>, bill@twwells.uucp (T. William Wells) writes:
> In article <8@estinc.UUCP> fnf@estinc.UUCP (Fred Fish) writes:
> ...
> : I was recently helping out a freshman CS major with her C homework and
> : found out, to my horror, that the teacher in the course was marking
> : off points for code which included braces when they weren't strictly
> : required.  They were teaching her to write code like:
> :
> :       inchar = getchar ();
> :       while (inchar != EOF)
> :               if (inchar == 0)
> :                       goto done;
> :               else
> :                       inchar = getchar ();
> : done: return inchar;
> :
> : Ickkk!!!
> 
> Double Ickkkk!!!! A goto where a break would have done.

This is yet another tripple icky example of CS professors
thinking that just because they can get the example programs
in K&R to compile, and because they did work in Fortran in
their thesis on astrophysics, they are qualified to teach
C (or any other language).  Wrong, wrong, wrong.

Any C guru qualified (in my humble opinion) to teach
C would be trying to teach code which looks like:

	/*
	 * assume students have not learned the ',' operator yet
	 */
	do	{
		inchar = getchar();
		} while(inchar != EOF && inchar);
	return inchar;

Personally, I haven't decided whether the while should be lined
with the do or the loop body yet, but I like the brace alignment
this way.
-- 
	Christopher J. Calabrese
	AT&T Bell Laboratories
	att!ulysses!cjc		cjc@ulysses.att.com

peter@ficc.uu.net (Peter da Silva) (12/25/88)

In article <11037@ulysses.homer.nj.att.com>, cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) writes:
> 	/*
> 	 * assume students have not learned the ',' operator yet
> 	 */
> 	do	{
> 		inchar = getchar();
> 		} while(inchar != EOF && inchar);
> 	return inchar;

I would recommend in this instance to make the test experession:

	inchar != EOF && inchar != '\0'

Since inchar is obviously not a boolean (it has three distinct possible
values: EOF, 0, and anything else).
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
Opinions may not represent the policies of FICC or the Xenix Support group.

mat@mole-end.UUCP (Mark A Terribile) (12/27/88)

: : ... helping out a freshman CS major with her C homework [I] found out ...
: : that the teacher ... was marking off points for code which [used] braces
: : when they weren't strictly required.  They were teaching her to write ...:
: :
: :       inchar = getchar ();
: :       while (inchar != EOF)
: :               if (inchar == 0)
: :                       goto done;
: :               else
: :                       inchar = getchar ();
: : done: return inchar;
: :
: : Ickkk!!!
: Double Ickkkk!!!! A goto where a break would have done.

Let's see how many violations of good form we can see.

There's the use of a goto, period.
There's the use of a goto where a break would serve.
There's the use of an else after a goto or break.  (Some would praise this.
	I don't.  See the example on p. 45 of Kernighan and Plaugher, *The
	Elements of Programming Style*, featuring the label ``NEXT_C'' .
	It's a splendid example of dead-spot-in-code-before-else.)
There's the use of a goto to break multiple levels of structure without
	closing braces to remind the reader how many levels are being broken.
There are two seperate calls to getchar() at opposite ends of the loop, one
	for the first pass, and one for all subsequent passes.
There are two adjacent levels of control structure, both omitting braces.  This
	is not only a readability disaster, but a maintainance nightmare.
There's the use of a goto and label to fold surruptitiously two exits from the
	loop into one.  It's really tough to see at a glance both the goto-exit
	and the loop's natural exit-from-the-top.
There's the use of a `` goto X; ... X: return y; ''  If the purpose of the
	loop is to return a value at a certain point, then the return ought to
	be right in the loop, with the bottom exit return a special case.
There's the treatment of two effectively symmetrical cases in vastly different
	ways--return on EOF by the loop's control clause, and return on value
	zero by a goto, and what is worse, a goto that purports (by it's
	placement in the if-else) to be coordinate (rather than subordinate or
	superior) to the loop-continuation operation.

Whew!  That's enough for the moment.  I'd deem it a favor to future generations
of programmers and to the industry as a whole if someone would collect the
responses from the net and mail them to the wall-eyed buzzard, and to that
buzzard's superiors.  And I'll bet a very nice dinner that I've written more
code for which customers ultimately paid real dollars than he has.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/27/88)

In article <11037@ulysses.homer.nj.att.com> cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) writes:
>In article <271@twwells.uucp>, bill@twwells.uucp (T. William Wells) writes:
>> In article <8@estinc.UUCP> fnf@estinc.UUCP (Fred Fish) writes:
>> : ...  They were teaching her to write code like:
>> :       inchar = getchar ();
>> :       while (inchar != EOF)
>> :               if (inchar == 0)
>> :                       goto done;
>> :               else
>> :                       inchar = getchar ();
>> : done: return inchar;
>Any C guru qualified (in my humble opinion) to teach
>C would be trying to teach code which looks like:
>	do	{
>		inchar = getchar();
>		} while(inchar != EOF && inchar);
>	return inchar;

Here's mine.  The exact formatting is NOT IMPORTANT.  What DOES matter
is the comments and the fact that it is obvious how one gets each
possible return value.

	#include	<stdio.h>

	#define	MAGIC	'\0'	/* silly terminating character value */

	int			/* returns EOF or MAGIC (why??) */
	some_function( void )	/* ANSI C assumed; else delete "void" */
		{
		int	c;	/* character from standard input */

		while ( (c = getchar()) != EOF )
			if ( c == MAGIC )
				return MAGIC;

		return EOF;
		}

pcg@aber-cs.UUCP (Piercarlo Grandi) (01/03/89)

In article <11037@ulysses.homer.nj.att.com> cjc@ulysses.homer.nj.att.com (Chris Calabrese[mav]) writes:

#   In article <271@twwells.uucp>, bill@twwells.uucp (T. William Wells) writes:
#   > In article <8@estinc.UUCP> fnf@estinc.UUCP (Fred Fish) writes:
#   > ...
#   > : I was recently helping out a freshman CS major with her C homework and
#   > : found out, to my horror, that the teacher in the course was marking
#   > : off points for code which included braces when they weren't strictly
#   > : required.  They were teaching her to write code like:
#   > :
#   > :       inchar = getchar ();
#   > :       while (inchar != EOF)
#   > :               if (inchar == 0)
#   > :                       goto done;
#   > :               else
#   > :                       inchar = getchar ();
#   > : done: return inchar;
#   > :
#   > : Ickkk!!!
#   > 
#   > Double Ickkkk!!!! A goto where a break would have done.

#   This is yet another tripple icky example of CS professors
#   thinking that just because they can get the example programs
#   in K&R to compile, and because they did work in Fortran in
#   their thesis on astrophysics, they are qualified to teach
#   C (or any other language).  Wrong, wrong, wrong.
#   
#   Any C guru qualified (in my humble opinion) to teach
#   C would be trying to teach code which looks like:
#   

#   	/*
#   	 * assume students have not learned the ',' operator yet
#   	 */
#   	do	{
#   		inchar = getchar();
#   		} while(inchar != EOF && inchar);
#   	return inchar;
#   
#   Personally, I haven't decided whether the while should be lined
#   with the do or the loop body yet, but I like the brace alignment
#   this way.

I would beg to suggest the following for the loop:

    for
    (
	inchar = fgetc(stdin);
	inchar != EOF && inchar != '\0';
	inchar = getc(stdin)
    );

Just to make it evident that this is a sequential scan. I use fgetc(3) to
initialize inchar because it does not get expanded inline (unless of course
I knew that in most cases the loop would be exited immediately)..

The following solution is more compact and arguably more in the C tradition,
but I think that making explicit the iteration structure with a for(;;) and
the explicit test against '\0' are somewhat more readable.

    while ((inchar = getchar()) && inchar != EOF);
-- 
Piercarlo "Peter" Grandi			INET: pcg@cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science	UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)

fransvo@htsa.uucp (Frans van Otten) (01/03/89)

In article <9235@smoke.BRL.MIL> gwyn@brl.arpa writes:
>	#include	<stdio.h>
>	#define	MAGIC	'\0'	/* silly terminating character value */
>	int			/* returns EOF or MAGIC (why??) */
>	some_function( void )	/* ANSI C assumed; else delete "void" */
>		{
>		int	c;	/* character from standard input */
>		while ( (c = getchar()) != EOF )
>			if ( c == MAGIC )
>				return MAGIC;
>		return EOF;
>		}

How do you like it my way:

#include <stdio.h>

int f()
  { int ch;
    while ((ch = getchar()) != EOF  &&  c)    /*  find EOF or '\0'  */
    return (ch);
  }

Any C programmer will understand how this function works; it takes less
space, because it is shorter, etc. So: Why is my solution too simple ?

-- 
                         Frans van Otten
                         Algemene Hogeschool Amsterdam
			 Technische en Maritieme Faculteit
                         fransvo@htsa.uucp

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/04/89)

In article <683@htsa.uucp> fransvo@htsa.UUCP (Frans van Otten) writes:
>In article <9235@smoke.BRL.MIL> gwyn@brl.arpa writes:
>>	#define	MAGIC	'\0'	/* silly terminating character value */
>How do you like it my way:
>    while ((ch = getchar()) != EOF  &&  c)    /*  find EOF or '\0'  */
>Any C programmer will understand how this function works; it takes less
>space, because it is shorter, etc. So: Why is my solution too simple ?

There is more to programming than simply writing code to short-range
specs.  My approach has the following practical advantages:
	1)  The role of the "magic" terminating character is clear.
	2)  It is easier to comprehend, because the different return
	    conditions are clearly spelled out.
	3)  Questionable points of the design were flagged.  In a real
	    project, these would be investigated and probably revised.
	4)  If the magic character ever needs to be changed, it is easy
	    to do in my version, and virtually impossible to go wrong.
If this sounds like an ad for Kernighan & Plauger's "The Elements of
Programming Style", well...

decot@hpisod2.HP.COM (Dave Decot) (01/05/89)

> In article <9235@smoke.BRL.MIL> gwyn@brl.arpa writes:
> >	#include	<stdio.h>
> >	#define	MAGIC	'\0'	/* silly terminating character value */
> >	int			/* returns EOF or MAGIC (why??) */
> >	some_function( void )	/* ANSI C assumed; else delete "void" */
> >		{
> >		int	c;	/* character from standard input */
> >		while ( (c = getchar()) != EOF )
> >			if ( c == MAGIC )
> >				return MAGIC;
> >		return EOF;
> >		}
> 
> #include <stdio.h>
> 
> int f()
>   { int ch;
>     while ((ch = getchar()) != EOF  &&  c)    /*  find EOF or '\0'  */
>     return (ch);
>   }
> 
> Any C programmer will understand how this function works; it takes less
> space, because it is shorter, etc. So: Why is my solution too simple ?

Aside from the fact that it contains a missing semicolon that will cause the
fragment to fail and will not be caught by the compiler, and a use of
two undefined identifiers (c and EOF) that will cause it to generate an
error message, what you meant:

  #include <stdio.h>
  int f()
    { int ch;
      while ((ch = getchar()) != EOF  &&  ch)    /*  find EOF or '\0'  */
  	  ;
      return (ch);
     }

works fine.  However, I would prefer to express the intent and usage
more clearly, as:

    #include <stdio.h>

    /*
       f() discards standard input characters until EOF or null byte is read.
       Returns EOF for EOF; '\0' for null byte.
    */

    int f()
    {
	register int c;		/* input character */

	    while ((c = getchar()) != EOF && c != '\0')
		;

	    return c;
    }

Dave Decot
decot%hpda@hplabs.hp.com

fransvo@htsa.uucp (Frans van Otten) (01/05/89)

David T. Sandberg ({amdahl,hpda}!bungia!nis!mictl!dts) mailed me about
my posting (edited):

<< #include <stdio.h>
<< 
<< int f()
<<   { int ch;
<<     while ((ch = getchar()) != EOF  &&  c)    /*  find EOF or '\0'  */
<<     return (ch);
<<   }
<
<Methinks thou needeth another semicolon, or thy while loop doth return
<after thy first iteration... also, what the undefined 'c' variable is
<intended to contain I won't guess, but in any event it seems useless
<to use a variable to store a constant expression.  Lastly, the
<conditional expression is parsed as ((ch = getchar()) != (EOF && c)),
<which finally compares the gotten character to the result of the
<Boolean expression (EOF && c)... either a 0 or a 1, depending on whether
<c is zero or nonzero.

I agree on the semicolon; the c should, of course, have been ch (How did
you guess that it was a variable ? :-) ). So far for the typos.  What you
write about the expression parsing is not true: In my C book it sais that
the != operator has a higher priority than the && operator, so the
expression will be parsed like:

  ( ( ( (ch = getchar() )  != EOF )  &&  ( ch ) )

Which makes it clear (to me) that the while loop terminates either at
EOF or when ch == '\0'.

<I understand the basis of what you are espousing, and agree that putting
<the whole test into the conditional expression is the way to go.  Here is
<what I would do... you'll note that it is closer to your idea than Doug's,
<but should work:
<
<#include <stdio.h>
<
<int func()
<}
<    int ch;
<    do {
<        ch = getchar();
<    } while ((ch != EOF) && (ch != '\0'));
<    return(ch);
<}

It won't work. Try an opening { to start the function block.
By the way, I never use a  do {} while ();  because I personally
don't like such a structure. But then again, I have more stupid
and unbased ideas.

<I'd post this as an article, but I don't have the capability to post
<news from this site.  ;'(  Feel free to quote from it and tear me limb
<from limb... I've got nothing better to do than read about it...  ;')

-- 
                         Frans van Otten
                         Algemene Hogeschool Amsterdam
			 Technische en Maritieme Faculteit
                         fransvo@htsa.uucp

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/06/89)

In article <9272@smoke.BRL.MIL>, I wrote:
>My approach has the following practical advantages: ...

I inadvertently left out an important one:
	5)  It is easy to change to return function values different from
	    EOF or the terminating magic character, for example true/false.