mautner@odin.ucsd.edu (Craig Mautner) (09/25/90)
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
Internet: 75746.3411@compuserve.com
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
mautner@cs.ucsd.edu Dept of CSE, C-014
(619) 534-4526 La Jolla, Ca. 92093vd09+@andrew.cmu.edu (Vincent M. Del Vecchio) (09/26/90)
> Excerpts from netnews.comp.lang.c: 25-Sep-90 Seven Original Sins of K&R > .. Craig Mautner@odin.ucsd. (8365) > 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 | | Pittsburgh, PA 15213 \ BITNET: vd09+%andrew@cmuccvma.bitnet | | (412) 268-4441 \ Internet: vd09+@andrew.cmu.edu | +----------------------------------------------------------------------------+
gillies@m.cs.uiuc.edu (09/26/90)
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 9tom@ssd.csd.harris.com (Tom Horsley) (09/26/90)
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?
--
======================================================================
domain: tahorsley@csd.harris.com USMail: Tom Horsley
uucp: ...!uunet!hcx1!tahorsley 511 Kingbird Circle
Delray Beach, FL 33444
+==== Censorship is the only form of Obscenity ======================+
| (Wait, I forgot government tobacco subsidies...) |
+====================================================================+rv@erix.ericsson.se (Robert Virding) (09/26/90)
In article <12780@sdcc6.ucsd.edu>, mautner@odin.ucsd.edu (Craig Mautner) writes: > 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. > 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. > III > {static} Granted. > 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. >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. > 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 > 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 :-). > 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". > 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? :-)
mcdonald@aries.scs.uiuc.edu (Doug McDonald) (09/26/90)
In article <4700066@m.cs.uiuc.edu> gillies@m.cs.uiuc.edu writes: > >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: >main() >{ >int x,i; >x=1; >switch(x) { > case 1: > for (i=0; i < 10; i++) goto 2; > case 2: > printf("%d ",i); >} >} Doug McDonald
goudreau@dg-rtp.dg.com (Bob Goudreau) (09/26/90)
In article <12780@sdcc6.ucsd.edu>, mautner@odin.ucsd.edu (Craig Mautner) writes: > > 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 62 Alexander Drive goudreau@dg-rtp.dg.com Research Triangle Park, NC 27709 ...!mcnc!rti!xyzzy!goudreau USA
roy@phri.nyu.edu (Roy Smith) (09/27/90)
goudreau@dg-rtp.dg.com (Bob Goudreau) writes: >> 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 roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy "Arcane? Did you say arcane? It wouldn't be Unix if it wasn't arcane!"
jh4o+@andrew.cmu.edu (Jeffrey T. Hutzelman) (09/27/90)
rv@erix.ericsson.se (Robert Virding) writes: >In article <12780@sdcc6.ucsd.edu>, mautner@odin.ucsd.edu (Craig >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 */ } 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 Internet/BITNET:jh4o+@andrew.cmu.edu, jhutz@drycas.club.cc.cmu.edu >> Apple // Forever!!! <<
goudreau@dg-rtp.dg.com (Bob Goudreau) (09/27/90)
In article <1990Sep26.193626.721@phri.nyu.edu>, roy@phri.nyu.edu (Roy Smith) writes: > goudreau@dg-rtp.dg.com (Bob Goudreau) writes: > >> The Second Original Sin was the failure to make "NULL" a keyword. Please keep your attributions straight; I did not write that sentence. > 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 62 Alexander Drive goudreau@dg-rtp.dg.com Research Triangle Park, NC 27709 ...!mcnc!rti!xyzzy!goudreau USA
maunz@warwick.ac.uk (The Teenage Student WINJA Turbot) (09/27/90)
In article <1990Sep26.193626.721@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: > >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. /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \ \/ /. \ JANET maunz@uk.ac.warwick.cu / "As the people here grow \/\/ I N J A \ (K R Turner) / colder..." -- Kate Bush \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
maunz@warwick.ac.uk (The Teenage Student WINJA Turbot) (09/27/90)
In article <1990Sep27.073730.26575@warwick.ac.uk> maunz@warwick.ac.uk (The Teenage Student WINJA Turbot) writes: >In article <1990Sep26.193626.721@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: >> >>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! >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. /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \ \/ /. \ JANET maunz@uk.ac.warwick.cu / "As the people here grow \/\/ I N J A \ (K R Turner) / colder..." -- Kate Bush \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
roy@phri.nyu.edu (Roy Smith) (09/27/90)
I wrote: > #define NULL (""[1]) maunz@warwick.ac.uk (The Teenage Student WINJA Turbot) responded: > B L E U G H ! ! You have such a way with words :-). It is clear from the various bits of mail I've gotten, and postings such as this, that folks on this group don't think too highly of my idea. Part of the problem is that I made a braino (similar to a typo, but occuring above the neck); I meant to write: #define NULL (""[0]) It's also clear that people probably won't think too highly of that either, so I guess we can just drop it. -- Roy Smith, Public Health Research Institute 455 First Avenue, New York, NY 10016 roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy "Arcane? Did you say arcane? It wouldn't be Unix if it wasn't arcane!"
henry@zoo.toronto.edu (Henry Spencer) (09/27/90)
In article <1990Sep26.193626.721@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: >What about this for a portable way to define NULL: > >#define NULL (""[1]) > >would that work? Uh, to do what? NULL is a null *pointer*, not a '\0' character. (That should be [0], and in any case this will not work in initializers because it is not a compile-time expression under the official rules.) -- TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology OSI: handling yesterday's loads someday| henry@zoo.toronto.edu utzoo!henry
merriman@ccavax.camb.com (09/28/90)
In article <1990Sep26.193626.721@phri.nyu.edu>, roy@phri.nyu.edu (Roy Smith) writes: > goudreau@dg-rtp.dg.com (Bob Goudreau) writes: >>> 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 > roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy > "Arcane? Did you say arcane? It wouldn't be Unix if it wasn't arcane!" NULL is a pointer type! NUL is an ASCII character!
jeenglis@alcor.usc.edu (Joe English Muffin) (09/28/90)
tom@ssd.csd.harris.com (Tom Horsley) writes: >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. C's array semantics make perfect sense once you understand C's *pointer* semantics, which are probably the most unique (and elegant, IMHO) feature of the language. The only wart I can see on the language wrt. arrays is that int foo(bar) char bar[]; { ... } is legal syntax. >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. Actually, it's probably _strings_ that have boggled beginners with backgrounds in BASIC, causing confusion and core dumps, dismaying dozens of dumbfounded dopes, than anything else. How many times have *you* seen a C neophyte go nuts trying to figure out why 'string1 = strcat(string2,string3);' doesn't work as expected? Of course, strings make perfect sense too once you understand pointers. I hardly consider these things an 'original sin.' They're natural extensions of a fundamental part of the language, which is really quite simple to understand. --jeenglis@alcor.usc.edu
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/28/90)
In article <4700066@m.cs.uiuc.edu>, gillies@m.cs.uiuc.edu writes: > 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); > } > } Easily: main() { int i; for (i = 0; i < 10; i++) printf("%d ", i); exit(0); /* you shouldn't leave this out */ } This was possible because of the assignment x=1. If that assignment had been x=2, the effect would have been undefined because i was not initialised. That's a good reason not to jump into loops even if C lets you. -- Fixed in the next release.
s64421@zeus.usq.edu.au (house ron) (09/28/90)
goudreau@dg-rtp.dg.com (Bob Goudreau) writes: >In article <1990Sep26.193626.721@phri.nyu.edu>, roy@phri.nyu.edu (Roy >Smith) writes: >> >> #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. I think he means #define NULL (""[0]) -- Regards, Ron House. (s64421@zeus.usq.edu.au) (By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350)
henry@zoo.toronto.edu (Henry Spencer) (09/28/90)
In article <1990Sep27.131329.26616@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: >... I meant to >write: > >#define NULL (""[0]) Roy, apart from not being a compile-time value, which limits its use, this is exactly and precisely equivalent to #define NULL 0 Might one ask what you are trying to accomplish with it? -- Imagine life with OS/360 the standard | Henry Spencer at U of Toronto Zoology operating system. Now think about X. | henry@zoo.toronto.edu utzoo!henry
rhealey@digibd.com (Rob Healey) (09/28/90)
In article <12777@sdcc6.ucsd.edu> 75746.3411@compuserve.com writes: >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. > > Seven Original Sins of K&R > by Philip J. Erdelsky > Compuserve: 75746,3411 > Internet: 75746.3411@compuserve.com > September 22, 1990 > Just general comment on the whole document: C wasn't designed to be a general purpose language, it was designed to help in the porting of an OS. C is a language that is more useful for OS work than for intro to programming 101. C is also not for people who have traditionally had their hands held by a compiler, i.e. strong typing and a plethora of data types. C is best used in situations where you need to avoid strong typing rather than encourage it. Most of the complaints in this article would be best solved if the author used the correct language for the task, one with strong typing and features that held your hands along the way so you didn't have to think as hard or be as careful. C isn't the only language in the world, use the language that best fits your need. These people who want A language to be all things to all applications are attacking the problem from the wrong angle. If I want quick, simple and dirty BASIC does a good job. If I want to do a device driver and feel too lazy to use assembly I'll use C. If I want to do database work I'll use SQL or a 4GL. If I want to do expert systems I'll use LISP, scheme or an OOL. As the man said: "The right tool for the right job" Rather than turning C into the Ada from HELL, use a better language for your needs. 'Nuff said, -Rob Speaking for self, not company.
roy@phri.nyu.edu (Roy Smith) (09/29/90)
henry@zoo.toronto.edu (Henry Spencer) writes: > Roy, apart from not being a compile-time value, which limits its use, > this is exactly and precisely equivalent to > #define NULL 0 > Might one ask what you are trying to accomplish with it? One might, but it probably wouldn't do much good at this point. As somebody pointed out to me in email, the first rule of holes is that when you're in one, you should stop digging. Suffice it to say it was a half-baked idea and I wish I hadn't brought it up in the first place. -- Roy Smith, Public Health Research Institute 455 First Avenue, New York, NY 10016 roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy "Arcane? Did you say arcane? It wouldn't be Unix if it wasn't arcane!"
goudreau@dg-rtp.dg.com (Bob Goudreau) (09/29/90)
In article <1990Sep28.112637.10446@zeus.usq.edu.au>, s64421@zeus.usq.edu.au (house ron) writes: > goudreau@dg-rtp.dg.com (Bob Goudreau) writes: > > >In article <1990Sep26.193626.721@phri.nyu.edu>, roy@phri.nyu.edu (Roy > >Smith) writes: > >> > >> #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. > > I think he means > > #define NULL (""[0]) ... which is still wrong, though at least it's a legal array access. The NUL character ('\0') is *not* the same as the null pointer. See the FAQ posting for details. ---------------------------------------------------------------------- Bob Goudreau +1 919 248 6231 Data General Corporation 62 Alexander Drive goudreau@dg-rtp.dg.com Research Triangle Park, NC 27709 ...!mcnc!rti!xyzzy!goudreau USA
userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (09/29/90)
In article <1990Sep28.112637.10446@zeus.usq.edu.au>, s64421@zeus.usq.edu.au (house ron) writes: >goudreau@dg-rtp.dg.com (Bob Goudreau) writes: > >>In article <1990Sep26.193626.721@phri.nyu.edu>, roy@phri.nyu.edu (Roy >>Smith) writes: >>> >>> #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. > >I think he means > > #define NULL (""[0]) > >-- >Regards, > >Ron House. (s64421@zeus.usq.edu.au) >(By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350) Wait a minute here. Am I missing something? Wouldn't (""?0?) be a pointer to a null (zero length) string rather than a NULL pointer (i.e. a pointer not pointing validly)? -------------------+------------------------------------------- Al Dunbar | Edmonton, Alberta | this space for rent CANADA | -------------------+-------------------------------------------
salomon@ccu.umanitoba.ca (Dan Salomon) (10/02/90)
In article <sazwbR600Vp6IHhVVV@andrew.cmu.edu> vd09+@andrew.cmu.edu (Vincent M. Del Vecchio) writes: > 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. Much more code is going to be written in C than currently exists. Should we sacrifice all the code to come for the sake of the existing code? -- Dan Salomon -- salomon@ccu.UManitoba.CA
rns@se-sd.SanDiego.NCR.COM (Rick Schubert) (10/02/90)
[I know I should probably let this go since this is a dead issue, but I couldn't resist improving on Henry's answer. I hope I'm not missing something, since I'm surprised he didn't also say what I'm going to.] In <1990Sep28.144753.23727@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <1990Sep27.131329.26616@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: >>... I meant to >>write: >> >>#define NULL (""[0]) >Roy, apart from not being a compile-time value, which limits its use, >this is exactly and precisely equivalent to >#define NULL 0 Since (""[0]) is not a compile-time value (I assume that's the same thing as a constant expression), it is also not a null-pointer constant. It DOES have the value 0, but the only arithmetic expressions that are null pointers are those that are constant expressions evaluating to 0. -- Rick Schubert (rns@se-sd.sandiego.NCR.COM)
hp@vmars.tuwien.ac.at (Peter Holzer) (10/02/90)
rv@erix.ericsson.se (Robert Virding) writes: >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. Like in: 1: for (;;) { 2: /* code */ 3: if (expression) break; 4: /* more code */ 5: } If break would break out of the surrounding if, it would not break out of the loop, so line 3 would just be a noop. -- | _ | Peter J. Holzer | Think of it | | |_|_) | Technische Universitaet Wien | as evolution | | | | | hp@vmars.tuwien.ac.at | in action! | | __/ | ...!uunet!mcsun!tuvie!vmars!hp | Tony Rand |
seanf@sco.COM (Sean Fagan) (10/03/90)
In article <1990Sep26.134716.17540@ux1.cso.uiuc.edu> mcdonald@aries.scs.uiuc.edu (Doug McDonald) writes: >Well, in a C-like language WHERE THE CASES DIDN'T FALL THROUGH >you could write: >>switch(x) { >> case 1: >> for (i=0; i < 10; i++) > goto 2; >> case 2: >> printf("%d ",i); Which, of course, prints out 0 *only*, which is not what the original did at all (although, I will admit, the original wasn't very clever, interesting, novel, obfuscated, but it was rather stupid). -- -----------------+ Sean Eric Fagan | "Never knock on Death's door: ring the bell and seanf@sco.COM | run away! Death really hates that!" uunet!sco!seanf | -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor") (408) 458-1422 | Any opinions expressed are my own, not my employers'.
dts@quad.sialis.mn.org (David T. Sandberg) (10/03/90)
In article <1990Oct2.040019.1635@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: >Much more code is going to be written in C than currently exists. >Should we sacrifice all the code to come for the sake of the existing >code? Apples and oranges. Maintaining backward compatibility doesn't "sacrifice" all future code... it just means that you can't have every toy construct you may want. That in and of itself doesn't prevent you from using the language, and is not nearly so serious as the problems that would be caused by breaking most every bit of existing code (a real, quantifiable sacrifice). -- \\ David Sandberg \ ,=, ,=, \\ // dts@quad.sialis.mn.org / | |uadric '=,ystems // \\ uunet!rosevax!sialis!quad!dts \ '=\ `=' \\
henry@zoo.toronto.edu (Henry Spencer) (10/04/90)
In article <3945@se-sd.SanDiego.NCR.COM> rns@se-sd.SanDiego.NCR.COM (Rick Schubert) writes: >Since (""[0]) is not a compile-time value (I assume that's the same thing >as a constant expression), it is also not a null-pointer constant. Wups. This is not my week. -- Imagine life with OS/360 the standard | Henry Spencer at U of Toronto Zoology operating system. Now think about X. | henry@zoo.toronto.edu utzoo!henry
rns@se-sd.SanDiego.NCR.COM (Rick Schubert) (10/04/90)
In <1990Oct3.172542.26794@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <3945@se-sd.SanDiego.NCR.COM> rns@se-sd.SanDiego.NCR.COM (Rick Schubert) writes: >>Since (""[0]) is not a compile-time value (I assume that's the same thing >>as a constant expression), it is also not a null-pointer constant. >Wups. This is not my week. In all fairness, though, this didn't occur to me until I saw your posting. -- Rick Schubert (rns@se-sd.sandiego.NCR.COM)
browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) (10/05/90)
M> Followup-To: > Lines: 29 WARNING: Nit about to be picked. In <1990Sep28.144753.23727@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >>In article <1990Sep27.131329.26616@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes: >>>... I meant to >>>write: >>> >>>#define NULL (""[0]) > >Roy, apart from not being a compile-time value, which limits its use, >this is exactly and precisely equivalent to > >#define NULL 0 Not exactly or precisely. Every time the first version is invoked, it creates a separate instance of a one-byte string. So you chew up static data storage. Depending on how your compiler does alignmnet, it may be two or four bytes each time--or more. And in large model with Microsoft C, some combinations of options could put each "" in its own data segment! Is that horse dead yet? Lord knows I've been beating it enough! :-) The above is my own opinion and not attributable to any other person or organization. email: browns@iccgcc.decnet.ab.com Stan Brown, Oak Road Systems, Cleveland, Ohio, U.S.A. (216) 371-0043
bls@u02.svl.cdc.com (Brian Scearce) (10/05/90)
browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) writes: >>>In article <1990Sep27.131329.26616@phri.nyu.edu> > roy@phri.nyu.edu (Roy Smith) writes: >>>>#define NULL (""[0]) This is the same as #define NULL '\0' >>#define NULL 0 This is the same as #define NULL 0 Both are different from #define NULL (void *)0 Neither of the suggested #defines are guaranteed to work with not-all-bits-0-for-NULL implementations if you pass NULL as a parameter to a function with no prototype in scope. >Not exactly or precisely. Every time the first version is invoked, it >creates a separate instance of a one-byte string. There's that, too.
henry@zoo.toronto.edu (Henry Spencer) (10/05/90)
In article <26661@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: >This is the same as #define NULL '\0' >This is the same as #define NULL 0 > >Both are different from #define NULL (void *)0 > >Neither of the suggested #defines are guaranteed to work with >not-all-bits-0-for-NULL implementations if you pass NULL as a >parameter to a function with no prototype in scope. There is *no*, repeat *no*, definition of NULL that is guaranteed to work with not-all-bits-0-for-NULL implementations if you pass NULL as a parameter to a function with no prototype in scope. Actually, this is true even if null pointers are all-0-bits, because they may not all be the same size. Repeat after me, 512 times: The representation of different pointer types can be different. To turn NULL into a valid null pointer of a particular type, the compiler must know the exact type that is desired. In the absence of prototypes, the only way to give the compiler this information in function calls is to explicitly cast NULL to the desired type. No definition of NULL can ever remove the need for this, and lazy programmers are just going to have to learn to put the casts in. No legal program can tell the difference between #define NULL 0, #define NULL 0L, and #define NULL ((void *)0). (Even prototypes do not fully remove the need to be aware of this issue, since varargs functions still need the casts.) -- Imagine life with OS/360 the standard | Henry Spencer at U of Toronto Zoology operating system. Now think about X. | henry@zoo.toronto.edu utzoo!henry
henry@zoo.toronto.edu (Henry Spencer) (10/05/90)
I wrote: > No legal program can tell the difference between #define NULL 0, > #define NULL 0L, and #define NULL ((void *)0). Well, if you want to be really picky, something like "sizeof(NULL)" can, but no proper use of NULL as a pointer can. -- Imagine life with OS/360 the standard | Henry Spencer at U of Toronto Zoology operating system. Now think about X. | henry@zoo.toronto.edu utzoo!henry
mercer@npdiss1.StPaul.NCR.COM (Dan Mercer) (10/06/90)
In article <1990Oct2.040019.1635@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: :In article <sazwbR600Vp6IHhVVV@andrew.cmu.edu> vd09+@andrew.cmu.edu (Vincent M. Del Vecchio) writes: :> 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. : :Much more code is going to be written in C than currently exists. :Should we sacrifice all the code to come for the sake of the existing :code? :-- : :Dan Salomon -- salomon@ccu.UManitoba.CA Regardless of what changes are made to the language there will always be problems for some in living within the languages limitations. The skill of a programmer is in coping with those difficulties. You cannot abandon previously written code and expect people to upgrade. However, not all the changes proposed would affect previously written code. For instance, implementation of a break label; capability would not affect previously written code. As for myself, I am more comfortable using flags (after getting burned by a nasty bug in PL1 code I wrote breaking out of a label). -- Dan Mercer Reply-To: mercer@npdiss1.StPaul.NCR.COM (Dan Mercer) "MAN - the only one word oxymoron in the English Language"