[comp.lang.c] style

PETERSC0%VUCTRVAX.BITNET@wiscvm.wisc.EDU (07/17/87)

    I'm sure I'll get jumped on for this, but what the heck...

    As far as I am concerned there is no justification (unless you know
that one form is clearly better than the other for your compiler and
machine) to use ++index over index++ (or vice versa).  Since my latest
project is being written in Pascal (grumble, grumble, no C for our main
VAXen), I long for either or both of these functions!  I forgot to
mention one other case to be made for one or the other of the above, if
your program/sub-program depends on which way it goes, it obviously makes
a difference...

    The main quibble I have with C programmers (none of you, of course) in
general is that they get carried away with the famed terseness and compact-
ness of C.  They tend to compact their valiables and declarations and
everything that they control until it is (often) unreadable to most non-
gurus.  It may be my heritage as a Pascal (and even Cobol) programmer or
the fact that my prof.s are killing me with 'style' issues, but I like to
know what the program means at a glance...

    I really only see two classes of style issues.  The first is the issue
of whether or not you make your names/definitions clear.  The second is
how you place your grouping symbols (begin/end and {/}) and how far you
squash your statements (1/line or 10/line).  The rest (except for comments,
which I won't go into) is personal...

    The fire-retardent suit is on, so flame away...

Chris Petersen
petersc0@vuctrvx1.bitnet
"Dr. Tachyon, I presume?"

jfjr@mitre-bedford.arpa (Freedman) (04/26/88)

  C provide tags and typdefs ie

I can make the following declaration

struct some_tag_name {
                  some_more_stuff
                }

or 

typedef struct {

                 some_stuff
  
               } some_type_name.

I can do similar things with enum.

 Now, as a former Pascal programmer I like the typedef method
MUCH better than the tag method. My question is this: Is
there any reason one method is preferred over the other?
(except for declarations for structure which will include
pointers -for trees, lists,etc)

Jerry Freedman, Jr      "Love is staying up all night 
jfjr@mitre-bedford.arpa   with a sick child,
(617)271-4563            or a healthy adult"

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/27/88)

In article <13115@brl-adm.ARPA> jfjr@mitre-bedford.arpa (Freedman) writes:
> Now, as a former Pascal programmer I like the typedef method
>MUCH better than the tag method. My question is this: Is
>there any reason one method is preferred over the other?

Typedef was added to C after struct tags.  For the most part it is
more convenient to use typedef.  Sometimes it is easier to use tags,
though, as in
	struct my_tag {
		struct my_tag *link;
		data_t data;
	};

tps@chem.ucsd.edu (Tom Stockfisch) (04/27/88)

In article <7770@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <13115@brl-adm.ARPA> jfjr@mitre-bedford.arpa (Freedman) writes:
>> Now, as a former Pascal programmer I like the typedef method
>>MUCH better than the tag method...
>Typedef was added to C after struct tags...Sometimes it is easier to
>use tags, though, as in
>	struct my_tag {
>		struct my_tag *link;
>		data_t data;
>	};


In this case you can use

	typedef struct LIST {
		struct LIST	*link;
		data_t		data;
	}	LIST;

since tags and typedefs are in different overload classes.
This usage is not strange looking if you think of the
initial "struct LIST" as meaning "BEGIN LIST DECLARATION"
and the final "LIST;" as "END LIST DECLARATION".
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu

dsill@nswc-oas.arpa (Dave Sill) (04/28/88)

Tom Stockfisch writes:
>In this case you can use
>
>	typedef struct LIST {
>		struct LIST	*link;
>		data_t		data;
>	}	LIST;
>
>since tags and typedefs are in different overload classes.
>This usage is not strange looking if you think of the
>initial "struct LIST" as meaning "BEGIN LIST DECLARATION"
>and the final "LIST;" as "END LIST DECLARATION".

Yuck.  Although legal, taking advantage of separate name spaces
like this is material for Obfucated C Code Contest entries.

This example also comflicts with the popular convention of using
uppercase-only names for macros.

=========
The opinions expressed above are mine.

Trivia Question: What is the origin of `uppercase'?

tps@chem.ucsd.edu (Tom Stockfisch) (04/29/88)

In article <13154@brl-adm.ARPA> dsill@nswc-oas.arpa (Dave Sill) writes:
>Tom Stockfisch [THAT'S ME] writes:
>>In this case you can use
>>
>>	typedef struct LIST {
>>		struct LIST	*link;
>>		data_t		data;
>>	}	LIST;
>>
>>since tags and typedefs are in different overload classes.
>>This usage is not strange looking if you think of the
>>initial "struct LIST" as meaning "BEGIN LIST DECLARATION"
>>and the final "LIST;" as "END LIST DECLARATION".
>
>Yuck.  Although legal, taking advantage of separate name spaces
>like this is material for Obfucated C Code Contest entries.

Everyone's entitled to their opinion.  This is, however, essentially
what happens in C++, where you get an automatic typedef of the same
name for every struct tag.  Are you saying that you would want to save
the tag for a different use, as in

	typedef int	LIST;
	struct LIST	{ ... };	?

If not, why object?

>This example also comflicts with the popular convention of using
>uppercase-only names for macros.

For better or for worse, there are many different conventions for
upper/lower case and capitalized/uncapitalized.
I quit using lower case names for typedefs after running into the
pcc bug (I've been told it's in all pcc compilers and will never
be fixed) in which local (auto) declarations do not hide outer typedef
names, even tho this is guaranteed in K&R p. 206 (1st ed.):

	typedef float	distance;
	...
	{
		auto int	distance;

The above won't work on my compiler.  Hence, the all-caps for typedefs.
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu

throopw@xyzzy.UUCP (Wayne A. Throop) (12/16/88)

In the code fragment posted in this line of conversation, there was
one "style fault" that could actually qualify as a bug under draft
X3J11, and which therefore I felt ought to be pointed out.

Now when I got done with the posting, I found I had picked on four
more points of style in the code fragment, and my posting had ended up
looking like a hatchet job rather than a warning of a nonportable
practice.  Well, rather than pare down my nits to the most important
one, I'm posting the whole critique.  I hope folks won't take this as
the hatchet job it superficially resembles, but will take in the way
it was intended: an important warning followed by four stylistic
afterthoughts that I really and truely think result in code of
"superior style".  Happy coding, and if you feel I've been too harsh
despite the disclaimer, feel free to email me and vent your spleen.

The fragment in question is:

    void strupr( s )
    char s[];
    {
            int p = 0;
            while ( s[p] != NULL ) {
               s[p] = toupper( s[p] );
               p++;
            }
    } /* strupr */

My comments, in decreasing order of urgency (or increasing order of
pickiness) are these.

First, comparing a character to NULL is stylistically wrong in K&R C,
since NULL is to be used in pointer contexts (just as FALSE or NO or
whatnot is to be used in "boolean" contexts).  In draft X3J11 C, this
is even a potential error, since NULL can legitimately be defined as
((void *)0), in which case an implementation (I think) is allowed to
diagnose an error in the above comparison.

Second, the loop control is scattered over the body of a while, which is
exactly what the for loop was invented for.

Third, the function might as well return s instead of void, so that
it can be slipped unobtrusively into expressions instead of forcing
separate statements or awkward expressions.

Fourth, it isn't indicated that ctype.h ought to be included.
(This is, of course, fairly obvious, and may have been omitted on
 purpose...)

Fifth, the object of this excersize is somewhat more naturally cast in
terms of pointers rather than subscripting in C.  Two marginal
justifications for this are that first it is more natural to step
along an array once by pointers, and second compilers with few or no
optimizing smarts will generate better code for the pointer case on
most (but not all) architectures. (This, of course, is a really picky,
obnoxiously finicky nit.)

Applying all of these, we get the "improved" fragment (using prototypes):

    #include <ctype.h>
    char *strupr( char *s ) {
        register char *p;
        for( p=s; *p != '\0'; p+=1 )
            *p = toupper( *p );
        return( s );
    }

Note that some might prefer the condition in the for loop to be

        *p != 0
or just
        *p

(In fact, I prefer just *p myself, but most folk seem to prefer the
 explicit comparison to a character value.)

--
"Leave him alone.  He is already neutralized."
"I don't want neutral.  I want dead."
                                        --- exchange in "Die Hard"
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

msb@sq.uucp (Mark Brader) (12/20/88)

Wayne A. Throop (throopw@xyzzy.UUCP) made, in <2404@xyzzy.UUCP>, some
criticisms of a certain piece of code including these lines:

> >           int p = 0;
> >           while ( s[p] != NULL ) {

The last of these was:

> Fifth, the object of this exercise is somewhat more naturally cast in
> terms of pointers rather than subscripting in C.

Wayne went on to cite two admittedly minor justifications for this.
And I'd like to add another: avoiding the use of "int" for the subscript!

Remember that "int" is allowed to be as small as 16 bits.  It is quite
conceivable that s[] has more than 32767 elements in it, so p can
overflow, followed by God-knows-what (or as the X3J11 people say, by
"undefined behavior").  A similar problem can exist if we make p "unsigned";
in this case it would be an infinite loop.

On the other hand, some compilers wouldn't allow the object's dimension
to exceed an int's range, so declaring p as "long" could be wasteful.

If we use pointers instead of subscripts to step through the array,
no such problem can exist.  A pointer that points to the beginning of
an array is guaranteed to be incrementable to the end of the array
(plus one more time, in Draft ANSI C); and there is only one size of
pointer variable (in true C, anyway): the right size.

Mark Brader				"Those who do not understand UNIX
SoftQuad Inc., Toronto			 are condemned to repeat it."
utzoo!sq!msb, msb@sq.com				-- Henry Spencer

throopw@xyzzy.UUCP (Wayne A. Throop) (12/29/88)

    As larger nits have lesser nits
    Upon their backs to bite 'em,
    The lesser have still lesser nits,
    And so ad infinitum.

Chris Siebenmann (ziebmef!cks) reminds that my "correction" of an
earlier code fragment is itself flawed.  I had a loop as

    #include <ctype.h>
    char *p, *s;
    ...
    for( p = s; *p; ++p )
        *p = toupper( *p );

Nearly as I can tell, dpANS says that loop ought to have been

    for( p = s; *p ++p )
        if( *p >= 0 )
            *p = toupper( *p );

because all functions defined in ctype.h take arguments that
are integers, but give defined results only if those integers have
values representable as unsigned integer (or are the constant EOF).

Thus, the test for negative values is (I *think*) necessary.  Unless,
of course, you are willing to otherwise ensure that s only points at
strings of vanilla characters... then the loop is OK as it was.

--
The program itself is the only complete description
of what the program will do.
                                        --- P.J. Davis
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

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

In article <2537@xyzzy.UUCP>, throopw@xyzzy.UUCP (Wayne A. Throop) writes:
>     #include <ctype.h>
>     char *p, *s;
>     ...
>     for( p = s; *p; ++p )
>         *p = toupper( *p );

> Nearly as I can tell, dpANS says that loop ought to have been

>     for( p = s; *p ++p )
>         if( *p >= 0 )
>             *p = toupper( *p );

Gee, I always do this:

	for(p = s; *p; p++)
		if(islower(*p))
			*p = toupper(*p);

While dpANS might have decided that toupper should bounds check, there
are too many V7-oid compilers out there that it's better to put the
bounds check in. Personally, I think that toupper should have been left
the way it was. Everything else in stdio forces you to do your own bounds
checking, so why should this be an exception?
-- 
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.

bdb@becker.UUCP (Bruce Becker) (12/30/88)

In article <2537@xyzzy.UUCP> throopw@xyzzy.UUCP (Wayne A. Throop) writes:
>[...]
>    for( p = s; *p ++p )
>        if( *p >= 0 )
>            *p = toupper( *p );
>
>because all functions defined in ctype.h take arguments that
>are integers, but give defined results only if those integers have
>values representable as unsigned integer (or are the constant EOF).
>
>Thus, the test for negative values is (I *think*) necessary.  Unless,
>of course, you are willing to otherwise ensure that s only points at
>strings of vanilla characters... then the loop is OK as it was.


	I'd like to point out a (possibly icky) variant -


		for( p = s; *p ++p )
			*p = toupper( *p&0xff );


	This gets at possible 256-character sets in the
	environments where the compiler &/| hardware has
	sign-extended the negative byte value.
	Not all _ctype arrays have the same range - some
	are only 128 bytes. In those cases the '0xff' above
	becomes '0x7f'.
	It might be useful to add that testing for EOF is
	possible - this raises the question of its value.
	Ought it to be -1, or 0xFF, or what? I'm confused
	about what the value of "toupper(EOF)" should be...


>Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

Cheers,
-- 
   _  _/\	Bruce Becker	Toronto, Ont.
   \`o O|	Internet: bdb@becker.UUCP, bruce@gpu.utcs.toronto.edu
    \(")/	BitNet:   BECKER@HUMBER.BITNET
---mm-U-mm---	"The OSF is suffering from Penix envy" - Rocky Raccoon

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

In article <189@becker.UUCP> bdb@becker.UUCP (Bruce Becker) writes:
>	It might be useful to add that testing for EOF is
>	possible - this raises the question of its value.
>	Ought it to be -1, or 0xFF, or what? I'm confused
>	about what the value of "toupper(EOF)" should be...

EOF is not required to be defined as -1, but that is really the
most practical choice in every environment I've seen.  It must
NOT be the same as a possible character value, so 0xFF is wrong.

I don't think EOF is supposed to be a valid argument for toupper(),
just for the is*() functions.

bill@twwells.uucp (T. William Wells) (01/06/89)

In article <2581@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
: In article <2537@xyzzy.UUCP>, throopw@xyzzy.UUCP (Wayne A. Throop) writes:
: >     #include <ctype.h>
: >     char *p, *s;
: >     ...
: >     for( p = s; *p; ++p )
: >         *p = toupper( *p );
:
: > Nearly as I can tell, dpANS says that loop ought to have been
:
: >     for( p = s; *p ++p )
: >         if( *p >= 0 )
: >             *p = toupper( *p );
:
: Gee, I always do this:
:
:       for(p = s; *p; p++)
:               if(islower(*p))
:                       *p = toupper(*p);
:
: While dpANS might have decided that toupper should bounds check, there
: are too many V7-oid compilers out there that it's better to put the
: bounds check in. Personally, I think that toupper should have been left
: the way it was. Everything else in stdio forces you to do your own bounds
: checking, so why should this be an exception?

There are two distinct issues:

    1) The signedness of a character.
    2) The range checking of islower/toupper.

If the character array may contain any character which is not
guaranteed to have a positive value, the *p may generate a negative
value. This will blow away many if not most islower's and toupper's.
This means that if that possibility exists, one must either use
unsigned characters or handle the negative values which may be
produced.

Once one has made sure that no negative values will make it into
toupper, one must also handle the case of toupper's that don't work
unless the character is a lower case letter. This means using
something like islower as well.

Combining the two code fragments above, the one with the sign test,
and the one with the islower test, will produce code that works for
all situations.

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

imp@Solbourne.COM (Warner Losh) (01/16/91)

In article <12075.279314fc@ecs.umass.edu> gerst@ecs.umass.edu writes:
>CDC uses quite a nice style for everything in their NOS/VE operating
>system.

For what it is worth, VMS does the same sort of things (although the
details vary slightly).  I found it useful when I was hacking in
MACRO-32, but less useful in 'C'.  The best reason to do it is that
you don't polute the user's name space, which is a growing problem in
C (and various add on libraryies).

Warner

-- 
Warner Losh		imp@Solbourne.COM
We sing about Beauty and we sing about Truth at $10,000 a show.