read(fd,&y,sizeof(y))

Guy Harris guy at rlgvax.UUCP
Sun Mar 25 12:33:34 AEST 1984


> I think you should curb your dogma, Guy.

Sorry, my dogma is trained as a watchdog and has to bark at intruders.

> I see a degree of cleanness in the basic datatype promotions from small
> ints to "generic" ints, and small floats to "generic" floats (that is,
> doubles) when passed as parameters, and I believe that that specification
> was made with the intention to aid in simplifying compiler implementation
> [ and not just because the architecture of the pdp11 demanded it, as
>   suggested to me in a previous letter ].

It's nice that you believe that, but do you have any evidence to back up
that belief?  Have you asked Dennis Ritchie about this?  By the way,
the architecture of the PDP-11 *doesn't* demand it.  Any instruction which
pushes a byte onto the stack decrements the stack pointer by two, so if
you do a

	movb	frobozz,-(sp)

it'll push a word onto the stack.  However, *nothing* in the PDP-11 architecture
requires that the program referencing frobozz at some offset "frob(sp)"
reference it with word instructions.  And I don't see why it's any cleaner
than the alternative.  As for floats and doubles, my uninformed guess (which
is worth neither more nor less than your uninformed guess) is that one
reason they promote floats to doubles in general is that they didn't want
to have to write a compiler which generated "setd" and "setf" instructions.
Fine, but it doesn't elevate the notion of "design your language around the
person writing the compiler" to a general design principle.  In fact, taken
as such a principle, it's flatly *wrong*.

> And I see no reason why this concept should not be generalized to
> pointers as well.  Passing a character as an argument to a function
> without an explicit cast is hardly reckless abandon; K&R say that
> chars are members of the int family and are treated that way.  Why should
> passing a pointer be any more stringent?

I see no reason why it *should* be generalized to pointers.  Again, your
comparison of "char" <-> "int" and "xxx *" <-> "char *" missed the point -
K&R says "char"s are members of the "int" family but does NOT say ANYTHING
remotely similar about a "pointer family".  As such, passing characters
without explicit casts isn't reckless abandon because K&R says explicitly
that there is such a cast, but passing pointers without explicit casts is
dangerous and wrong because K&R does not promise that any such cast will
be done.  If you don't like the C language's rules for dealing with
pointers as parameters, fine; say that the language should be changed.  Just
don't add your own rules on top of K&R and claim that it's part of C.

To quote from your original article:

> I don't think this is non-portable.  For a machine which has pointers of more
> than one width, the compiler can be expected to widen the shorter ones to
> the width of the largest as it is pushed onto the argument list, just as
> chars are promoted to ints when pushed.  The called function will know it's
> stored that way and shorten it if it needs to before it's used.

This statement is flatly false.  No exceptions, no appeals.  There exist
implementations of C in which the code

	read(fd,&y,sizeof(y));

will not properly execute.  (Proof by counterexample.)  Your claim that
"the compiler can be expected to widen the shorter ones... just as chars
are promoted to ints" is equally incorrect - see the same counterexample,
and see K&R and notice the lack of any such claim.  C is not what people
want it to be; pending either an ANSI C language standard, or public release
of any of AT&T's internal C language standards, C is what K&R says it is.
No more, no less.  If you deny that, you're denying that there is any
authoritative reference manual to C, which would render it useless as a
language for writing portable code.

(By the way, I also note the use of the word "pushed" in the paragraph
quoted.  The term "passed as an argument" should be used, because there's
no guarantee that parameters will be passed on a simple stack.  It indicates
that a lot of the thinking on this question is based on the low-level details
of how C is implemented.  If C is to be used as a portable implementation
language, however, people will just have to forget what they know about the
C implementation most of the time and target their code for an abstract C
implementation; otherwise, when their code is ported to a C implementation
that doesn't reproduce the characteristics of the implementation they wrote
the code for, it may not work.)

> It seems so much more conceptually clean to me to say that a (foo *) is
> a member of the pointer family and give the compiler implementors (and
> program writers) a break.

Again, why is this more conceptually clean?  I haven't thought of pointers
as a generic data type since I stopped programming in PL/I, lo these many
years ago.  ALGOL 68, PASCAL, Modula-2, Mesa, and many other languages have
"pointer" as an adverb, so that you have "pointer to int" and "pointer to
char" and "pointer to frobozz" - C is another of these languages.  Several
of these languages have a generic null pointer, but so does C, in a sense.

> That is why I think that null pointers should be represented as NULL,
> whose definition is 0 *cast to a pointer to anything you like*; I don't
> believe that it should make a difference whether it is a (char *) 0 or
> a (struct _iob *)0.

In all of these languages, except C, you declare the types of the arguments
to a procedure when you want to use the procedure, and the compiler can
automatically generate code to pass a null pointer of the appropriate type.
C currently lacks this facility.  Why not ask for that facility, instead
of changing the language in ways that:

	1) make current reasonable implementations non-conforming; and
	2) cause extra code to be generated (to cast the pointers to
	   this "generic" type when passing them as parameters, and to
	   cast them back to the appropriate type when the pointers
	   are used);

> My view is that program control and data management is complex enough
> as it is, and if by clustering basic operative groups {ints, floats, pointers}
> can free me from cast slavery then I would argue for it.

"program control and data management is complex enough as it is"?  Sorry, son,
if that's a plea for sympathy it fails miserably.  Running your code through
"lint" and throwing in a few casts doesn't cost much on top of the rest of
the work I hope you put into the code you write.  Referring to it as "cast
slavery" is cute but wrong.

> Fervent bible-thumping serves no purpose in a discussion which considers the
> merits and limitations of the standard(s); we /know/ what it SAYS;
> but you certainly hold no patent on its interpretation, or on what
> is worth cross-examining.

1) Show me where you can interpret K&R as *requiring* the treatment of pointers
you desire, not just *permitting* it (which it certainly does).  Otherwise,
my interpretation that it doesn't require your treatment of pointers *is*
the only correct one.  And, if that is the case, code which requires
that treatment of pointers is incorrect code, and is not guaranteed to
work on all implementations of C.

2) Throwing around terms like "Fervent bible-thumping" serves no purpose
in this discussion at all.

Here's what I said in the article you're responding to:

> Anyone who expects a C compiler to do this is going to be sorely disappointed.
> There is NOTHING in K&R which says that this must be done, and there is no
> reason for a compiler to do so.  It is explicitly stated in K&R that integer
> and floating point values are coerced to "int" and "double", respectively, so
> one would expect this to happen.

The second and third sentences are true, as anyone with a copy of K&R can
verify.  The first is also true, if what another poster says about the
Perq C compiler is true, namely that you *do* get bitten if you aren't
type-correct in your handling of pointers.

The rest of my article wasn't bible-thumping, it was expressing frustration
at dealing with code written by people who assume that 0 and NULL can freely
be passed to routines expecting pointers without casting them.  I have to pick
up the "core" files when such a program dies on our 68K-based machines, and
I have to fix them.  I'm justifiably tired of doing so.  (I'm also tired
of dealing with programs that either flatly assume that there's a null
string at whatever location NULL points to, or just assumes that trying to
dereference a NULL pointer is harmless; unfortunately, I suspect people are
going to continue to write that kind of code.  As such, I suspect that even
if C were changed to permit you to explicitly declare the arguments that
a function takes, people would still not bother using it and cause the same
old problems all over again.)

At this point, I say debate about the subject doesn't help much.  The facts
about how the language *is* (not how it *should be*) have been laid out more
times than I can count by several people; if people still aren't convinced that
until the language changes they'll just have to start casting their pointers,
they're not ever going to be convinced.  I'll just hope that most people start
casting their pointers properly, or that some way of declaring function argument
types enters the language and people start using it, and that I rarely have to
deal with code that doesn't properly coerce pointers.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy



More information about the Comp.unix.wizards mailing list