LWN.net Logo

Advertisement

Advanced thin client solution for Linux, based on Open Source. Mix Windows and Linux applications on the same desktop.

Advertise here

NULL v. zero

NULL v. zero

Posted Jul 22, 2004 18:59 UTC (Thu) by h.j.thomassen (guest, #15232)
Parent article: NULL v. zero

I would like to bring this discussion back to a plain vanilla C one.
It may help if you read K&R, 2nd Ed. page 102:

"Pointers and integers are not interchangeable. Zero is the sole exception: the constant zero may be assigned to a pointer, and a pointer may be compared with the constant zero. The symbolic constant NULL is often used in place of zero, as a mnemonic to indicate that this is a special value for a pointer"

The first edition has a similar text on page 97/98. So: NULL is a mnemonic to support readability: nothing more..

Hence the usual #define NULL 0 [And not: (void *)0 or (char *)0].

Statements like "ptr = 0" or "if (ptr != 0)" are perfectly legal C, but K&R have introduced NULL for better readability. Linus is right to follows K&R in this.
The use of NULL instead of 0 shows your collegues that you are aware that you used an exceptional language feature. But automated compiler checks are out of the question.

If a subroutine wants a ptr-argument, it is wrong to write "subr(0)", because it is not within the limits of the above K&R wordings. But "subr(NULL)" is equally wrong. In ANSI C the function-prototyping mechanism will "fix" this error for you on the fly. In pre-ANSI C, or in ANSI-C without a known prototype for your subr, you are lucky (but buggy nevertheless) if "sizeof(0)==sizeof(your_ptr)". Your program blows if this is not the case. I have seen a lot of this in the days when the first Motorola68000 C-compilers had the habit of giving two bytes to an int, and four bytes to a pointer.

But the comment by Kamil (above) with the "execl" example hits an exceptionally sore spot, since even the ANSI-prototype mechanism can not save you if the prototype is declared with a variable number of arguments. If you pass a 0 or a NULL as the argument to an execl, you get "sizeof(int)" zero-bytes on the argument stack. The subroutine expects "sizeof(const char *)" zero-bytes as a terminator. On modern 32-bit compilers those two sizes happen to be equal. But there is nothing in the C-language that requires them to be equal. The execl example really *must* have "(const char *)NULL" (or (const char *)0) to be theoretically correct in size.

Beware: history may repeat. The Motorola68000 example is from the days that we converted from 16-bit thinking to 32-bit thinking. The conversion from 32-bit to 64-bit thinking may uncover lots of similar problems.

And, by the way, there is nothing in the C standard that says that all pointers should be of equal size. I have seen one CPU-with-C-compiler where sizeof(int *) was 2, and sizeof(char *) was 3. Admittedly, this was 25 years ago.
But it is the reason why void-pointers were introduced in the first place.

The guarantee that the language gives you is that sizeof(void *) >= sizeof(any_other_data_ptr_type). The void-pointer was introduced because the language needed a "pointer-transport-crate", suitable to store (cast) any other type/size of data pointer into, without the risk of loosing precision.

From a theoretical point of view the above "execl" example might receive too many zero-bytes if you write (void *)0 instead of (char *)0. The (char *)0 is what the execl-prototype requires, and therefore the only correct pointer-type (and size!).

I think that the world would collapse if a compiler would come up now where not all pointers, including the void pointer, would have equal size; but that's a different topic.

Hendrik-Jan Thomassen


(Log in to post comments)

NULL v. zero

Posted Jul 23, 2004 14:36 UTC (Fri) by vivi48 (subscriber, #6412) [Link]

> The execl example really *must* have "(const char *)NULL" (or
> (const char *)0) to be theoretically correct in size.

or (void *)NULL or (void *)0 because the spec explicitely says that with va_arg you can read back a void * as a char *.

Copyright © 2008, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds