[comp.lang.c] Value of a null pointer

Paul_L_Schauble@cup.portal.com (04/23/88)

I don't want to start the null pointer discussion all over again. But I have
a co-worker claiming that C requires that a null pointer be binary zero. He
cites two reasons:
1. An uninitialized external is set to zero bits. C defines an uninitialized
   external pointer to be a null pointer. Therefore zero bits must be a null
   pointer.

2. One can use calloc to allocate an array of pointers. The initial value of
   this array must be null pointers. calloc sets the area to zero bits.
   Therefore.......

Unfortunately, I don't have a copy of the proposed ANSI standard. My
recollection is that in both cases the pointer values are undefined.

Also, does the new standard require that a cast of a literal zero always
does the right thing? That is, are
    ptr_type_var = (ptr_type)0;     /* assigns null pointer */
    ptr_type_var = 0;               /* assigns null pointer */
    func( (ptr_type)0 );            /* function expecting pointer type */

Are all of these always correct?

I believe that C does not require the null pointer to be zero and that there
are machines running it where the null pointer is non-zero. What I need, if
possible, are specific citations.

    Thanks,
      Paul

henry@utzoo.uucp (Henry Spencer) (04/24/88)

> 1. An uninitialized external is set to zero bits...

Wrong.  This was never made entirely clear in K&R, but ANSI C makes it
quite specific that an uninitialized external is set as if it were
explicitly initialized to 0.

> 2. One can use calloc to allocate an array of pointers. The initial value of
>    this array must be null pointers. calloc sets the area to zero bits.

Wrong.  Calloc sets its area to zero bits.  That is not guaranteed to be
zeros of any data type.  Well, if you read the fine print it's probably
guaranteed to be integer zeros, given that integers are pretty tightly
defined to be binary, but it is *not* guaranteed to be pointer or
floating-point zeros.

> Also, does the new standard require that a cast of a literal zero always
> does the right thing? That is, are
>     ptr_type_var = (ptr_type)0;     /* assigns null pointer */
>     ptr_type_var = 0;               /* assigns null pointer */
>     func( (ptr_type)0 );            /* function expecting pointer type */

Yes.  This was true in K&R and it is true in ANSI C.


Mind you, given the quantity of sloppy C code around, machine designers
interested in C and/or Unix will think twice about making NULL anything
but all-zero-bits, but they are within their rights to do so.
-- 
"Noalias must go.  This is           |  Henry Spencer @ U of Toronto Zoology
non-negotiable."  --DMR              | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

chris@mimsy.UUCP (Chris Torek) (04/24/88)

In article <4728@cup.portal.com> Paul_L_Schauble@cup.portal.com writes:
>... I have a co-worker claiming that C requires that a null pointer be
>binary zero. He cites two reasons:

[both are wrong]

>1. An uninitialized external is set to zero bits.

An uninitialised external is set to `zero'.  If the external is a
pointer, it is to be set to NULL, which may not be all zero bits.  (It
is true, as far as I know, that no existing Unix system bothers to
distinguish between pointers and other data.)

>2. One can use calloc to allocate an array of pointers. The initial value of
>   this array must be null pointers. calloc sets the area to zero bits.

The first and third statements are correct; the second is not.  Or
so says the dpANS, anyway.

>Also, does the new standard require that a cast of a literal zero always
>does the right thing?

Yes.

>I believe that ... there are machines running it where the null
>pointer is non-zero. What I need, if possible, are specific citations.

I have heard of one, or perhaps two, efforts at writing compilers for
machines on which the machine's preferred nil-pointer format was not an
all zero bit pattern of some appropriate size.  The implementors ran
into so much code that assumed otherwise that they finally gave in and
did runtime conversions and tests, rather than using the hardware nil
types.

In other words, when it comes to *existing implementations*, your
co-worker is probably right.  When it comes to definitions, he is wrong.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/25/88)

In article <4728@cup.portal.com> Paul_L_Schauble@cup.portal.com writes:
>He cites two reasons:
>1. An uninitialized external is set to zero bits. C defines an uninitialized
>   external pointer to be a null pointer. Therefore zero bits must be a null
>   pointer.

No, an uninitialized external datum is automatically initialized with
a zero of the right type.  The representation of this zero need not be
all zero bits, and it necessarily depends on the type.

>2. One can use calloc to allocate an array of pointers. The initial value of
>   this array must be null pointers. calloc sets the area to zero bits.
>   Therefore.......

calloc() initializes the allocated storage to zero byte (char) values.
That may or may not be suitable for interpretation as an array of
zero floating-point or null pointer values, depending on the architecture.

>    ptr_type_var = (ptr_type)0;     /* assigns null pointer */
>    ptr_type_var = 0;               /* assigns null pointer */
>    func( (ptr_type)0 );            /* function expecting pointer type */
>Are all of these always correct?

Yes, those are correct uses of null pointers.

The confusion probably arises because the following:
	0
can be used to initialize a pointer variable with a null pointer,
and it also will compare equal to a null pointer of any type.
The thing to realize is that the compiler may have to map that
apparently-integer-constant 0 into some strange internal form
when necessary to properly match the way that pointers are
represented.

bts@sas.UUCP (Brian T. Schellenberger) (04/29/88)

In article <11198@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
|
|[lots of very well-stated true stuff deleted]
|I have heard of one, or perhaps two, efforts at writing compilers for
|machines on which the machine's preferred nil-pointer format was not an
|all zero bit pattern of some appropriate size.  The implementors ran
|into so much code that assumed otherwise that they finally gave in and
|did runtime conversions and tests, rather than using the hardware nil
|types.

We have code running on two such machines (DG & CDC).  On both, you can 
zero out memory with your favorite fill function, and it will still work
just fine.  The first time an address register is loaded, it gets turned 
into the real null-pointer if it used to be binary zero.  Then it is stored.

This means that the only things that screw you up are type-punning (using two
different pointers to the same memory) or incorrect use of unions (which is
really just language-supported type punning).  So you can assign or even stuff
a binary zero into a pointer place, but it may not still look the same if
you examine it in some peculiar way.

This approach allows most sloppy C code to work.
-- 
                                                         --Brian.
(Brian T. Schellenberger)				 ...!mcnc!rti!sas!bts

. . . now at 2400 baud, so maybe I'll stop bothering to flame long includes.