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:
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:
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
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
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:
- 4.10p1 "Pointer conversions" on null pointer constants
- 4.11p2 "Pointer to member conversions" on null pointer constants
- 5.19p2 "Constant expressions" a null pointer is a constant expression
- 18.1 "Types" includes NULL from the C headers
- C.2.2.3p1 "Macro NULL" as from standard C headers, and used in C++
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:
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.
It's shorter than typing NULL.
It avoids the wrong definitions of NULL
- Do we need to make up any more reasons?
One thing we must admit is, that its harder to grep for.