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 void *
.
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
std::nullptr_t
.
Why does this make sense? In itself, and in light of the incompatibility of C?
A null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.
The type of NULL may be either an integer type or void * . This is because the C standard allows it to be defined as either an integer constant expression or the result of a cast to void * .
A null pointer is a pointer which points nothing. Some uses of the null pointer are: a) To initialize a pointer variable when that pointer variable isn't assigned any valid memory address yet.
A null value (often shortened to null) is a special value that means something has no value. When a pointer is holding a null value, it means the pointer is not pointing at anything. Such a pointer is called a null pointer.
In C, a void*
can be implicitly converted to any T*
. As such, making NULL
a 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 NULL
).
C++ introduced 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.
C does not simply define NULL
as (void *)0
. It's also possible to define it as 0
or any constant expression that evaluates to it. Using #define NULL 0
works in either language.
Edit: this answer is very good and more detailed.
My assumption has always been that implementations' decisions to keep NULL
as 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 NULL
to nullptr
would potentially break bad/old code, while doing very little to help good/new code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With