Overview on the NULL problem

Many people seem to want to use NULL when referring to the null-pointer. It seems this stems from the user having a history in C before learning C++. Let's discuss how C++ views the use NULL differently from C. From this discussion we hope to thoroughly confuse the issue, and then recommend a mandate for you to follow.

C NULL pointers

Here are common possible definitions of the NULL macro in C:

   1 #define NULL ((void*)0)
   2 /* or */
   3 #define NULL 0
   4 

The C standard allows both definitions. In C, this allows you to assign NULL to any other pointer types. This is because void* in C is a universal pointer type. C allows any void* to be assigned to any other pointer type, and it also allows any other pointer type to be stored in a void*. This allow the following code to work without any errors:

   1 #include <stdlib.h> /* Define NULL */
   2 char *p = NULL;

This works great in C.

The C++ difference

However, unlike pointers in C, pointers in C++ are strongly typed (except for implicit conversions to base class pointers, which open new and wonderful type holes). Thus, void* cannot be implicitly converted to any other pointer type without an explicit cast.

This means that if you write this:

   1 char *p = ((void*)0);

it would cause a compilation error (shown from g++ here):

error: invalid conversion from `void*' to `char*'

And if you would compile this using a C++ compiler

   1 #include <stdlib.h>
   2 char *p = NULL;

it might give you the same error message depending on how NULL is defined in your C header files. Of course, the correct C++ way of including NULL would be

   1 #include <cstdlib>
   2 char *p = NULL;

which will use the C++ definition of NULL and will not generate a compiler warning because the C++ header files properly define NULL as expected by C++ compilers.

Isn't NULL in the C++ Standard?

The C++ Standard has the following sections about NULL:

The only references to a macro called NULL appear in instances where a C header is used. Of course, C++ defines NULL differently even if these C headers are included. But do you really want to include one of these C headers just to use NULL? What if you want to use NULL pointers without a header file dependency?

NULL in the C++ standard

  18.1 Types          [lib.support.types]
  [...]
  The macro NULL is an implementation-defined C++ null pointer constant in this International Standard
4 (4.10). 180)
  [...]
180) Possible definitions include 0 and 0L, but not (void*)0.

  C.2.2.3 Macro NULL                                                                      [diff.null]
  The macro NULL, defined in any of <clocale>, <cstddef>, <cstdio>, <cstdlib>, <cstring>,
1 <ctime>, or <cwchar>, is an implementation-defined C++ null pointer constant in this International
  Standard (18.1).

It is also interesting to know what exactly is a null pointer constant.

  4.10 Pointer conversions                                                                            [conv.ptr]
  A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to
1 zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that
  type and is distinguishable from every other value of pointer to object or pointer to function type. Two null
  pointer values of the same type shall compare equal. [...]

How in C++ then?

Since 0 (zero) is the universal initializer for all pointer types in C++, it is used instead of the traditional C convention; and in fact, many programmers simply use 0 as a pointer initializer, like this:

   1 char *p = 0;

No error from that. So if you wanted to, you might do this:

   1 #define NULL (0)
   2 

Now you can use NULL without an error in that simple example.

Why did you say (0) there?

Surrounding macros in ()s prevents really stupid things. If you are not really stupid, or have no fear of stupidity, then feel free to define it without the ()s. Perhaps I will describe this in further detail in a future article someday.

g++ has __null

So now we come to another solution, which I know works in recent g++ versions at least:

   1 char *p = __null;

While it's nice that the compiler has this built into it, it's not an option for portable standard code, as far as I know. (If anyone can say otherwise, according to the C++ standard, please make a reference to the exact paragraph here.)

Does the author of this know that NULL is defined to __null for g++? Is this still not an option for portable code?

One more complication

So is 0 really sufficient everywhere? There are claims that 0 is a valid memory location on some architectures. But the C++ standard is pretty explicit about the zero literal. We see in 4.10p1 that "A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero." Now let's look at the sentence for a while. It talks about an expression, in code. It doesn't talk about the actual address of the null pointer. My toaster has a null pointer address of 0x715517, but C++ code still uses the literal zero to get it.

The Mandate

Use 0.

One thing we must admit is, that its harder to grep for.

NullOrZero (last edited 2010-09-12 14:54:28 by 109)