Why NULL is 0

Richard Harter g-rh at cca.CCA.COM
Fri Mar 18 03:11:16 AEST 1988


In article <636 at acer.stl.stc.co.uk> scott at acer.UUCP (Mike Scott) writes:

>If I could add my 2 pennyworth.  From K&R p192, we read " it is
>guaranteed that assignment of the constant 0 to a pointer will
>produce a null pointer distinguishable from a pointer to any object".
>
>From page 71: "Within a function, each argument is in effect a local
>variable initialized to the value with which the function was called."
>
>It follows at once from these that the integer 0 may be supplied in
>any function call where a pointer is expected, and the compiler must
>make sure that the proper translation to the correct sort of
>null pointer is performed.
>
>[I suppose one might argue about differences between 'assignment' and
>'initialisation'. I think it's clear that initialisation of a pointer
>to NULL (whatever NULL may be defined as) and assignment of NULL to
>that same pointer have to give the same result!]
>
>The real problem is that functions don't have to be declared until
>used. Given an ANSII-type declaration, the compiler can sort out
>the mess. Until then, I suppose the only way to get portable code is
>indeed to use expicit casts as in the "correct" code above.

Actually, the NULL=0 question is part of a more general problem that
may not be addressed correctly in ANSI C prototypes.

In a single routine there is no problem with NULL=0 because that usage
is guaranteed by the language.  The problem arises when we call one
routine from another and pass arguments.  For everything to work right
the calling routine must pass the right number of arguments to the
called routine, with all arguments having the right type.  The problem
is that the compiler has no way of knowing what these are -- it takes
it on faith from the code present in the routine that has the call.
In the case of an uncasted 0, it sees an integer, and sets up the
call as though it were passing an integer.  This fails unless, by chance,
the architecture is such that a NULL pointer and an integer 0 happen
to look alike.

However the problem is more general, and I am not sure that ANSI
function prototypes handle it properly.  [I don't have the spec,
so I am winging it a bit here.]  The problem breaks into three parts.
Part 1 is to provides a means for both the calling routine and the
called routine to have a description of the calling sequence.  Part
2 is to ensure that they have the *same* description.  Part 3 is to
ensure synchronization, i.e. to ensure that the routines affected
change when the description changes.

Function prototypes addresses the first question.  The second question
is the tricky one.  The natural way to do this is to put the decsription
in one place, which is shared by both caller and called routines.  In
the UNIX/C environment this means putting them in a header file.  It
also has implications for the called routine.  Does the called routine
still have an inline calling sequence declaration?  Look at this:

#include "prototypes.h"
....
type_of_foo foo(a,b)
  type_of_a a;
  type_of_b b;
{....}

I don't know if this is what ANSI C expects, but it's not too hot if
it is, because we now have two descriptions of the calling sequence.
The right thing is simply

#include "prototypes.h"
....
type_of_foo foo(a,b) {....}

In fact, even type_of_foo should be omitted, since that is really part
of the description.

I have the (perhaps mistaken) impression that ANSI function prototypes
cannot be set up this way in the called routine.  If they can't the next
best thing is for the compiler to check whether the function prototype
description in "prototypes.h" matches the actual declaration.

This may be even better from the standpoint of visibility, since the
contents of the header file containing the description are not visible
when you are looking at code referencing the the description.

Another issue is that the called routine may not even have a copy of
the description -- in that case the value of the description file is
much less, since the routine can change without the description file
changing and vice versa.

Part 3 (synchronization) can be handled using make with the right
dependencies, if the other problems are met.

These are some of the issues, as I see them.  I'm not sure that  the
ANSI C function prototypes deal with them all 'properly', but I
haven't seen anything on the net discussing the impact of prototypes
on the called routines.
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.



More information about the Comp.lang.c mailing list