Seven Original Sins of K&R (Long) 
Author Message
 Seven Original Sins of K&R (Long)

Quote:
> Excerpts from netnews.comp.lang.c: 25-Sep-90 Seven Original Sins of K&R

> None of these sins is inconsistent with the philosophy
> of C.  We needn't embrace heresies like Pascal, Modula
> 2 or Ada.  But we must abandon the false god of 100%
> upward compatibility.  We must tear down the old temple
> to build a new one.  Then, and only then, will our
> redemption be at hand.

I don't know about this.  There are (unfortunately) still so many
pre-ANSI compilers and so much pre-ANSI code (not to mention code that
depends on the existence of the other "sins" that you mentioned) in use
that it would be ridiculous for the time being to abandon backward
compatibility.  I like in general the style of the gcc, accepting both
older and newer code with command-line switches to specify explicitly
one or the other.  But pre-ANSI code will be around for a good while to
come.

+----------------------------------------------------------------------------+
| Vincent Del Vecchio     \ Disclaimer: Views expressed are not necessarily  |
| Box 4834                 \ those of any person/group I am associated with. |
| 5125 Margaret Morrison St.\   UUCP: {uunet,harvard}!andrew.cmu.edu!vd09    |


+----------------------------------------------------------------------------+



Sun, 14 Mar 1993 05:19:25 GMT  
 Seven Original Sins of K&R (Long)
My apologies for the consumption of bandwidth but I wanted
to send this through properly.  The last time it had the wrong
Subject line.

The author of this does not have access to the news groups.
He asked me to post this and see what comments it generates.
Any correspondence should be sent to him at the internet address
included in the header.

-Craig Mautner

//////////////////// Begin Included Message ////////////////////////

              Seven Original Sins of K&R
                 by Philip J. Erdelsky
                Compuserve: 75746,3411

                  September 22, 1990

The creation of C approximately two decades ago was a
wondrous event, even if it did not seem so at the time.  
Like all human creations, C was imperfect.  I have
identified seven Original Sins--minor flaws in C for
which K&R will eventually have to answer, in this world
or the next.  I call them original sins because they were
present when C originated, not because K&R were the
first to commit them.  Some of these sins have been
purged from later versions of C, but others remain with
us.

I am not the first to decry these sins, nor will I be
the last.  I am merely another in a long series of
prophets crying in the wilderness.

                           I

The First Original Sin was pitifully weak typing.  
There is no Boolean type in C, so generations of
programmers have erroneously written something like "if
(x=5)" instead of "if (x==5)", only to wonder why x
always seems to be 5, regardless of what has gone
before.  The "char" type was not specified as either
signed or unsigned.  This sin has probably wasted more
CPU time than any other, as savvy programmers learn to
put a defensive "&0xFF" after every "char" expression
that needs to be unsigned.  The default type for
functions should have been "void", not "int", but there
was originally no "void" type.

Modern compilers have provided partial redemption from
this sin, usually by issuing warning messages when the
program appears to be tainted.  But these warnings are
often false alarms and go unheeded.  There is still no
Boolean type, and "char" may be either signed or
unsigned.  Even the new enumeration types are merely
integers in disguise, just as willing to be mixed as
matched.

                          II

The Second Original Sin was the failure to make "NULL"
a keyword.  Beginning C programmers wonder why you have
to "#include <stdio.h>" in a program that doesn't use
standard I/O.  Some compilers don't even object when
you assign an integer constant to a pointer without a
typecast, especially when the constant happens to be
zero.  Don't blame the compiler.  The poor thing can't
tell the difference between a zero integer constant and
"NULL".

Redemption from this sin is on its way.  Modern
compilers define "NULL" as "(void *) 0", so there's at
least some hope of distinguishing it from a plain old
zero.

                          III

The Third Original Sin was the use of the keyword
"static" to mark a function or variable as local to
particular source file.  This is really a trinity of
sins.  The word "static" doesn't mean local.  It
conflicts with the other use of the word "static"--to
mark a variable inside a function as one that actually
is static, in an accepted meaning of the word.  
Finally, even if the word "local" had been used
instead, it would have been marking the wrong thing.  
The word "public", or some similar word, should have
been used to mark the few functions and variables that
must be made available to the code in other files.  
Other functions and variables should have been local by
default.  That's how it's done in assembly language and
other high-level languages, and the reason for it is
obvious.

From this sin, however, no redemption is in sight.

                          IV

The Fourth Original Sin is the mandatory use of the
"break" keyword to terminate a "case" clause in a
"switch" statement.  Omitting it is natural for
beginning programmers, and sometimes even for
experienced programmers who have been dabbling in more
tightly structured languages.  Of course, this causes
control to fall through to the next case, which is
occasionally useful but nearly always a mistake, like a
double exposure in photography.  But the evil goes even
further.  Often, the "switch" statement is enclosed in
a "for" or "while" loop.  You want to finish up a
"case" clause by breaking out of the loop?  You can't
do it in C, not without breaking out of the "switch"
statement first!

The solution, not likely to be adopted even in C+++,
would be to have the compiler put an implicit "break"
at the end of every "case" clause, and reserve the
"break" keyword for breaking out of loops, the way God
intended.

                           V

The Fifth Original Sin was the way functions are
defined.  The entire parameter list has to be written
twice.  That's something no programmer should have to
do unless it's absolutely necessary.  And to compound
the evil, an untyped parameter defaults to type "int".  
Most programmers have written something like
"strcmp(s,t)", forgetting the declaration "char
*s,*t;".  What you wind up with in most cases is, not a
function that fails, but something worse--a function
that works as long as pointers and integers are the
same size, and then fails when you try to port it.

Fortunately, ANSI C permits prototype definitions, but
the old way is still permitted, at least during a
transitional period.  Let's hope the transition is
brief.

                          VI

The Sixth Original Sin was the way conflicts among the
names of members of different structures were neither
forbidden nor resolved.  The original K&R said that
different structures could have members with identical
names as long as they had identical offsets.  The way
early compilers implemented this dictum varied.  Some
compilers would check to see that the offsets were
indeed identical.  Others simply generated erroneous
code when they weren't.  Most programmers took the
safest course by including the structure name--usually
abbreviated--in every member name.

Modern compilers have atoned for this sin completely by
keeping a separate member list for each structure type.  
This resolves the conflicts, but a reminder of past
iniquities persists in the awkward names of structure
members in UNIX source code and other old C scriptures.

                          VII

The Seventh Original Sin was the eight-character limit
on distinguishable names, or even fewer than eight for
externally defined names.  Of course, some such
limitation was required for efficient implementation,
but eight characters are not enough.  C was much better
than fortran, which allowed only six, but there are
many pairs of English words with distinct meanings
whose first eight letters are identical.  The minimum
number depends on the language, but for English about
20 should be sufficient.  German programmers need more.

Most modern compilers do have a reasonable limit, but
some compiler developers have apparently forgotten that
virtue lies in moderation.  One compiler allows at
least several hundred characters, maybe more.  That's
too long.  Compilers are supposed to compile, not test
the limits of computability by allowing single labels
to occupy practically the entire computer memory (and
disk swap area).  An unprintable name--one that won't
fit on a single line--should also be uncompilable.

                       Epilogue

None of these sins is inconsistent with the philosophy
of C.  We needn't embrace heresies like Pascal, Modula
2 or Ada.  But we must abandon the false god of 100%
upward compatibility.  We must tear down the old temple
to build a new one.  Then, and only then, will our
redemption be at hand.

                         Note

This jeremiad is not copyrighted.  You are welcome to
copy it and pass it on.  I only ask you to leave my
name and account number on it.  Let me take the
credit--and the heat.

//////////////////// End Included Message ////////////////////////
--
--------------------------------------------------------------------
Craig D. Mautner                UCSD

(619) 534-4526                  La Jolla, Ca. 92093



Sat, 13 Mar 1993 23:44:40 GMT  
 Seven Original Sins of K&R (Long)

Quote:

>              Seven Original Sins of K&R
>                 by Philip J. Erdelsky

>                           I
> {Weak typing, reaaly no bools and char neither signed or unsigned}
>         The "char" type was not specified as either
>signed or unsigned.  This sin has probably wasted more
>CPU time than any other, as savvy programmers learn to
>put a defensive "&0xFF" after every "char" expression
>that needs to be unsigned.

This is no REAL problem, if you are going to do operations which
should be unsigned, just declare the variables as 'unsigned char'. A
(really) savvy programmer would *NEVER* put a &0xff after every char
expression. A novice would.

Quote:
>                          II
>               Some compilers don't even object when
>you assign an integer constant to a pointer without a
>typecast, especially when the constant happens to be
>zero.  Don't blame the compiler.  The poor thing can't
>tell the difference between a zero integer constant and
>"NULL".

According to the language definition assigning a zero to a pointer is
perfectly legal, the compiler shouldn't complain. All C compilers I
have seen will complain for any other integer. For the 50 million'th
time in this group, there is no difference between zero and NULL.

Quote:
>                          III
> {static}

Granted.

Quote:
>                          IV
> {break}

What's the problem? "break" means break out of the surrounding
while/for/case. The REAL sin is that "break" ignores a surrounding if.
This really can cause problems.

Quote:
>The solution, not likely to be adopted even in C+++,
>would be to have the compiler put an implicit "break"
>at the end of every "case" clause, and reserve the
>"break" keyword for breaking out of loops, the way God
>intended.

I hope it is NEVER adopted! Being able to "fall through" is extremely
pratical and saves much code copying or "goto"s. Adding the "break" is
really no problem.

Quote:
>                           V
> {defining function arguments}
>Most programmers have written something like
>"strcmp(s,t)", forgetting the declaration "char
>*s,*t;".  What you wind up with in most cases is, not a
>function that fails, but something worse--a function
>that works as long as pointers and integers are the
>same size, and then fails when you try to port it.

Actually all compilers will complain when you try to USE "s" and "t"
as pointers

Quote:
>                          VI
> {struct member name conflicts}

True, but extremely practical. Saved typing, no need to define a union
of possible structures and adding union element names to every
reference :-).

Quote:
>                          VII
>{eight character name limit}

Agreed, but unfortunately C had/has to exist on systems which
themselves limit the name length (in linkers and such). We could I
suppose always say "don't run C on such systems".

Quote:
>                       Epilogue

>None of these sins is inconsistent with the philosophy
>of C.

If the sins are consistent with the philosophy of C would there
correction then be inconsistent? :-)


Sun, 14 Mar 1993 20:43:03 GMT  
 Seven Original Sins of K&R (Long)

Re: Sin #IV

Hey, how else can I write the following amazingly convoluted code
(idea courtest of Harbison & Steele's book, first edition):

main()
{
int x,i;
x=1;
switch(x) {
        case 1:
                for (i=0; i < 10; i++)
        case 2:
                printf("%d ",i);

Quote:
}
}

And the result:

0 1 2 3 4 5 6 7 8 9



Sun, 14 Mar 1993 09:20:00 GMT  
 Seven Original Sins of K&R (Long)
What? only seven?

In this list, the only one that seems unforgivable to me is VII - short
names, but you left out the most absolutely awful and despicable sin of all:

                    VIII

The eight (and worst) original sin was allowing arrays to (sometimes) be
kind of automatically converted sort-of into pointers to the first element
of the array except when they aren't. Without a doubt this psuedo
equivalence between arrays and pointers that works most of the time except
when it doesn't has caused more confusion and twisted more brains of people
trying to learn C than any other feature.  If I want the address of an
array, why not stick an '&' operator in front of it like I have to do for
EVERY OTHER kind of variable in C?
--
======================================================================

  uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
                                               Delray Beach, FL  33444
+==== Censorship is the only form of Obscenity ======================+
|     (Wait, I forgot government tobacco subsidies...)               |
+====================================================================+



Sun, 14 Mar 1993 19:39:23 GMT  
 Seven Original Sins of K&R (Long)

Quote:

>Re: Sin #IV

>Hey, how else can I write the following amazingly convoluted code
>(idea courtest of Harbison & Steele's book, first edition):

>main()
>{
>int x,i;
>x=1;
>switch(x) {
>    case 1:
>            for (i=0; i < 10; i++)
>    case 2:
>            printf("%d ",i);
>}
>}

>And the result:

>0 1 2 3 4 5 6 7 8 9

Well, in a C-like language WHERE THE CASES DIDN'T FALL THROUGH
you could write:

Quote:
>main()
>{
>int x,i;
>x=1;
>switch(x) {
>    case 1:
>            for (i=0; i < 10; i++)

                goto 2;

Quote:
>    case 2:
>            printf("%d ",i);
>}
>}

Doug McDonald


Sun, 14 Mar 1993 21:47:16 GMT  
 Seven Original Sins of K&R (Long)

writes:

Quote:

> The Second Original Sin was the failure to make "NULL"
> a keyword.  Beginning C programmers wonder why you have
> to "#include <stdio.h>" in a program that doesn't use
> standard I/O.  Some compilers don't even object when
> you assign an integer constant to a pointer without a
> typecast, especially when the constant happens to be
> zero.  Don't blame the compiler.  The poor thing can't
> tell the difference between a zero integer constant and
> "NULL".

Or better yet, how about a new operator named "nil", which takes
a type name (sorry, pointer types only need apply) and which evaluates
to the nil pointer of that type?  For example,

        char *  cp;

        ....

        if (cp == nil(char *)) ....

Of course, it's easy enough to implement now as a macro, but think
of all the comp.lang.c articles that could have been avoided by
building it into the language and thus avoiding having the token
"0" do double duty...

----------------------------------------------------------------------
Bob Goudreau                            +1 919 248 6231
Data General Corporation

Research Triangle Park, NC  27709       ...!mcnc!rti!xyzzy!goudreau
USA



Mon, 15 Mar 1993 00:39:27 GMT  
 Seven Original Sins of K&R (Long)

Quote:


>Mautner) writes:
>>              Seven Original Sins of K&R
>>                 by Philip J. Erdelsky

>>                          II
>>               Some compilers don't even object when
>>you assign an integer constant to a pointer without a
>>typecast, especially when the constant happens to be
>>zero.  Don't blame the compiler.  The poor thing can't
>>tell the difference between a zero integer constant and
>>"NULL".

>According to the language definition assigning a zero to a pointer is
>perfectly legal, the compiler shouldn't complain. All C compilers I
>have seen will complain for any other integer. For the 50 million'th
>time in this group, there is no difference between zero and NULL.

I know of one compiler (on a 16-bit micro) that will not complain if you
use any other integer or long int.  Pointers on that machine are
(exaclty) same as unsigned long ints, and the compiler lets you say

void function(void)
{
unsigned char *pointer;
unsigned long int integer;

integer=0xE0C000;
for(pointer=integer;!(*pointer && 0x80););      /* wait for keypress */
printf("%#04x",*pointer & 0x7F);  /* strip off flag bit */
integer=0xE0C010;
*pointer=0;     /* reset keyboard latch and/or advance buffer */

Quote:
}

which will wait for a keypress and print out its ASCII value (on an
Apple IIgs, under ORCA/C 1.0 or 1.1).
-----------------
Jeffrey Hutzelman
America Online: JeffreyH11

- Show quoted text -

Quote:
>> Apple // Forever!!! <<



Mon, 15 Mar 1993 05:49:07 GMT  
 Seven Original Sins of K&R (Long)

Quote:

>> The Second Original Sin was the failure to make "NULL" a keyword.

What about this for a portable way to define NULL:

#define NULL (""[1])

would that work?
--
Roy Smith, Public Health Research Institute
455 First Avenue, New York, NY 10016

"Arcane?  Did you say arcane?  It wouldn't be Unix if it wasn't arcane!"



Mon, 15 Mar 1993 03:36:26 GMT  
 Seven Original Sins of K&R (Long)

Quote:
(Robert Virding) writes:
>>{eight character name limit}

>Agreed, but unfortunately C had/has to exist on systems which
>themselves limit the name length (in linkers and such). We could I
>suppose always say "don't run C on such systems".

Hmm...  `Replace the linker' seems somewhat more sensible.  Yes, I know about
systems where the linker cannot be supplanted.  In such a case, use the
following scheme:

C Compiler:   C  -->  `C' object format
`C' Linker:     `C' object format  --> system object format
System Linker: system object format  --> executable

The `C' Linker delivers a single object file with externals `main' plus any
system calls[1].  Since |main| < 6 this eliminates the problem.

SR
[1] that is, it also handles the C libraries, your personal libraries, etc.
Everything except some start-up code and the system calls.
---



Mon, 15 Mar 1993 04:26:24 GMT  
 Seven Original Sins of K&R (Long)

Quote:
Smith) writes:

> >> The Second Original Sin was the failure to make "NULL" a keyword.

Please keep your attributions straight; I did not write that sentence.

Quote:
> What about this for a portable way to define NULL:

> #define NULL (""[1])

> would that work?

Nope; it's not even *defined* behavior to access beyond the end of
an array, which is what you've done.

----------------------------------------------------------------------
Bob Goudreau                            +1 919 248 6231
Data General Corporation

Research Triangle Park, NC  27709       ...!mcnc!rti!xyzzy!goudreau
USA



Mon, 15 Mar 1993 07:44:06 GMT  
 Seven Original Sins of K&R (Long)

Quote:

>What about this for a portable way to define NULL:

>#define NULL (""[1])

>would that work?

        B       L       E       U       G       H       !       !

This is a joke, right?
("") is a null-terminated empty string, no?
Functionally equivalent to a char pointer which refers to an ASCII NUL or
char (0), no?
(""[1]) is probably a char pointer to garbage, no?

Either this is a joke, or I have missed the point.
Either way I'm stupid.
I must agree with the poster/author of the 'original sins' about NULL though.
It would be nice if NULL had been made unnecessary by a standardised keyword
such as 'nullpointer' or something. But nobody could have expected K & R to
have crystal balls.

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

 \/\/ I N J A  \ (K R Turner)               / colder..." -- Kate Bush
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



Mon, 15 Mar 1993 15:37:30 GMT  
 Seven Original Sins of K&R (Long)

Quote:

>>What about this for a portable way to define NULL:

>>#define NULL (""[1])

>>would that work?

>    B       L       E       U       G       H       !       !

>This is a joke, right?
>("") is a null-terminated empty string, no?
>Functionally equivalent to a char pointer which refers to an ASCII NUL or
>char (0), no?
>(""[1]) is probably a char pointer to garbage, no?

Well that proves I'm stupid.
I meant (""[1]) is probably a garbage char, honest, your honour!

Quote:
>Either this is a joke, or I have missed the point.
>Either way I'm stupid.
>I must agree with the poster/author of the 'original sins' about NULL though.
>It would be nice if NULL had been made unnecessary by a standardised keyword
>such as 'nullpointer' or something. But nobody could have expected K & R to
>have crystal balls.

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

 \/\/ I N J A  \ (K R Turner)               / colder..." -- Kate Bush
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/


Mon, 15 Mar 1993 15:43:02 GMT  
 
 [ 27 post ]  Go to page: [1] [2]

 Relevant Pages 

1. seven deadly sins

2. seven deadly sins

3. The original Sins of "C"

4. Long sin function...

5. Long sin function...

6. How to keep debug information when a reference to the original directory is no longer seen

7. Help need sin(large number), sin: TLOSS error

8. char size (was long long long long long int)

9. Pointers & matrices: Twist on the original question

10. Q: sin & cos with gcc

11. Cos&Sin in DJGPP

12. The Sins of K&R

 

 
Powered by phpBB® Forum Software