I've been writing C++ for many years, using
nullptr for null pointers. I also know C, whence NULL originates, and remember that it's the constant for a null pointer, with type
For reasons, I've had to use
NULL in my C++ code for something. Well, imagine my surprise when during some template argument deduction the compiler tells me that my NULL is really a ... long. So, I double-checked:
#include <type_traits> #include <cstddef> static_assert(not std::is_same<decltype(NULL), long>::value, "NULL is long ???");
And indeed, the static assertion fails (with GCC and with Clang).
I checked on cppreference.com, and sure enough (C++11 wording):
The macro NULL is an implementation-defined null pointer constant, which may be an integer literal with value zero, or a prvalue of type
Why does this make sense? In itself, and in light of the incompatibility of C?
In C, a
void* can be implicitly converted to any
T*. As such, making
void* is entirely appropriate.
But that's profoundly dangerous. So C++ did away with such conversions, requiring you to do most pointer casts manually. But that would create source-incompatibility with C; a valid C program that used
NULL the way C wanted would fail to compile in C++. It would also require a bunch of redundancy:
T *pt = (T*)(NULL);, which would be irritating and pointless.
So C++ redefined the
NULL macro to be the integer literal 0. In C, the literal 0 is also implicitly convertible to any pointer type and generates a null pointer value, behavior which C++ kept.
Now of course, using the literal 0 (or more accurately, an integer constant expression whose value is 0) for a null pointer constant was... not the best idea. Particularly in a language that allows overloading. So C++11 punted on using NULL entirely over a keyword that specifically means "null pointer constant" and nothing else.
In both languages,
NULL is an implementation-defined null pointer constant. C++ section 17.2.3, which refers to C 7.19 for the definition.
That means that in C,
NULL can be defined as an integer type or as a
void* type, and in C++ can be defined as an integer type; it could also be defined as a
nullptr_t if I've interpreted the standard correctly. A hidden (non-normative) footnote says that
(void*)0 can't be a valid definition, and that makes sense because C++ doesn't have C's implicit conversion from
void* to other pointer types.
If you have a C compiler that defines it as
((void*)0) and a C++ compiler that defines it as
0L, they are both conformant. Both implementations satisfy the use cases (can assign from and compare with
nullptr primarily to give a typed value suitable for overloading, as it was considered surprising that passing
NULL to a function could select an integer version.
My assumption has always been that implementations' decisions to keep
0 was a matter of backwards compatibility with C++98. I've seen a lot of code using
NULL in non-pointer contexts, particularly as a (probably unintentional, or at least uninformed) substitute for a null terminator in an array. Since the best practice since '11 has been "don't use
NULL at all", redefining
nullptr would potentially break bad/old code, while doing very little to help good/new code.