Subject: Re: NULL return value checking
To: None <tech-kern@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-kern
Date: 04/23/2002 20:26:03
>> As far as I know, using NULL explicitly makes programs more portable
> False.  Replacing every occurrence of "if(p == NULL)" with "if(p)" or
> "if(p == 0)" or even "if(p == '\0')" (ewww!) [1] has precisely zero
> impact on the portability of the code.

Agreed - and indeed it may increase it, because there are probably
systems that do null pointer constants correctly but have NULL
misdefined.

What it does to its maintainability is another issue.  NULL is really a
peculiar form of comment, saying "I intend this to be a null pointer".
Unfortunately, because there is widespread confusion surrounding it, I
am of the opinion that using NULL is basically useless and sometimes
even counterproductive.  I have even seen code that assigns NULL to
objects of type char, what would correctly be written '\0', apparently
confusing "null pointer" with "NUL character" - it's unfortunate that
"NUL" and "null" are spelled so much alike.

> The place where the difference between NULL and 0 might have
> significance is as an argument to a function whose signature is not
> known to the compiler (varargs, or a function for which a prototype
> is not in scope),

Using it in such context, without a cast, is always incorrect - and
with a cast, you might as well write 0 anyway.  (Why is it incorrect
without a cast?  Because NULL can validly be defined as 0, in which
case without a cast you are passing an int, not a pointer, and the call
may go horribly wrong as a result.  Even if it's ((void *)0) or
equivalent, you're likely to be passing the wrong type of pointer.)

> and when doing memset() of memory which might include a pointer. [2]

I have trouble imagining what you'd use NULL for in a call to memset().

>> Assuming it is zero is technically incorrect.
> Assuming that the bit pattern stored in a pointer storing a "null
> pointer" is all-bits-zero is incorrect.

Agreed.  Indeed, I think very little is guaranteed about the bit
patterns the represent pointers; there is probably a guarantee that
copying the bit pattern copies the pointer value (eg, you can memcpy()
a block of memory including a pointer), but I think that equal pointer
values generated other ways are not guaranteed to be bit-identical.

> [2] I recall some debate about what types you were actually allowed
>     to memset(, 0, ); certainly unsigned char is OK, signed char is
>     probably OK, but there exist implementations where an
>     all-bits-zero pointer is NOT == NULL.

Are there any implementations where you mustn't memset a pointer to
all-0-bits even if you don't try to do anything with the resulting
pointer value?  For example, can you memset a structure to all-0-bits
and then immediately follow that with explicit assignments to its
pointer fields, and be safe?  I've seen it said that there are
architectures on which you can't do anything to certain invalid pointer
values, even load them from memory, but that's not to say they can't
exist in memory.

Of course, how much relevance this has to NetBSD is another question.
I've seen NetBSD code assume that all-0-bits is a nil pointer, and feel
confident there code that assumes that all pointer types are the same
size, or that copying a pointer from one type to another by copying the
bits is equivalent to a cast and assignment....

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B