Subject: Re: bin/7592: programs' error handle broken by good intentions
To: Todd Whitesel <toddpw@best.com>
From: Greg A. Woods <woods@most.weird.com>
List: netbsd-bugs
Date: 05/26/1999 04:38:56
[ On Tuesday, May 25, 1999 at 22:31:54 (-0700), Todd Whitesel wrote: ]
> Subject: Re: bin/7592: programs' error handle broken by good intentions
>
> > (I.e. the fact that when you pass 0 it is silently co-erced by the
> > prototype, but if you pass 1 you'll get the warning "passing arg 2 of
> > `err' makes pointer from integer without a cast".)
> 
> AFAIK the sneaky behavior of 0 is part of the language -- it's how you
> explain the equivalence of code like:
> 
> 	if (bufp == NULL)
> 
> 	if (!bufp)
> 
> My reading of the ANSI books has always led me to believe that the silent
> type-coercion of 0 is intentional, and not implementation defined.

Well, that's entirely possible (I don't have a copy of the current C
standard, just the 1999/01/18 draft of C9X).

What follows is a rant about "good intentions gone bad" that otherwise
isn't quite on-topic for this PR.

In traditional C the expression "(bufp == NULL)" was covered by "the
usual arithmetic conversions" i.e. if "NULL" is defined as a plain '0'
(as it always was -- NULL was just a more meaningful name for zero) and
"bufp" is declared as something somewhat different and perhaps wider
than an ordinary "int", such as a pointer to a "char", then the '0'
would be promoted to be the same width as that of the type of 'bufp',
and indeed pointers were merely integers (though perhaps with a unique
width and ), and any "null pointer" had the integer (albiet usually
wider than an "int") value of zero.  There was literally no difference
between pointers and "long"s w.r.t. the type conversions to/from "int"s
in assignment or equality operands, or function parameters.  Everything
was very clean and elegant.

I note that the c9x draft says that "An integer may be converted to any
pointer type [...]" and "An integer constant expression with the value 0
[...] is called a ``null pointer constant''."  Indeed the c9x draft goes
on to state that "If both operands of an equality operator have
arithmetic types then the usual arithmetic conversions are performed",
and it says much the same for assignment.  To further qualify pointers
by saying that "if one operand is a null pointer constant [then] it is
converted to the type of the other operand."  Further the c9x draft says
that type conversion of function parameters happens as if by assignment.

So, it appears that (at least in c9x) you are right:  the integer value
of 0 will indeed be treated specially when assigned to a pointer or
passed as a pointer value, even though this was not necessary in
traditional C.

This is unfortunate because it's still possible to call a function
without a prototype declaration in scope (i.e. within the definition of
the language), and passing zero as a parameter to such a function
expecting a pointer will potentially cause problems because this
automatic cast which might in fact widen the representation of zero to
something of greater rank than an ordinary 'int' will be missing (as it
most certainly will on many architectures if the same code is compiled
with an older non-Standard compiler, and as I say even c9x will still
permit traditional function definitions).  Standard C has apparently
sobattoged the ability of a standard compiler to warn of failed
backwards compliance.  It also means it is impossible to give any
non-zero integer values special meaning in relation to pointers (such as
-1 or ~0) and expect them to behave the same as zero does in assignments
and function parameters where pointer values are expected.

From the point of view of language elegance it's even more unfortunate
-- the basic elegance of pointers as integer types is lost and the
simple integer representation of '0' is clouded with dual purposes that
are not driven by the usual arithmetic conversions.  Of course that
elegance was broken by the dweeb(s) who insisted that something special
be made of "a null pointer constant" in the first place (in order to
permit at least one misguided compiler vendor to get away with "#define
NULL ((void *)0)", in case anyone doesn't remember any of the debates of
the original ANSI C standardisation effort).  They may as well have just
made NULL a keyword and been done with any formal association of null
pointers with the integer value of zero!

C is dead -- long live C!

-- 
							Greg A. Woods

+1 416 218-0098      VE3TCP      <gwoods@acm.org>      <robohack!woods>
Planix, Inc. <woods@planix.com>; Secrets of the Weird <woods@weird.com>