Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is C++'s NULL typically an integer literal rather than a pointer like in C?

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?

like image 664
einpoklum Avatar asked Sep 04 '21 16:09

einpoklum


People also ask

Why do we use null pointer in 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.

What datatype is null in C?

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 * .

Does C have null pointer?

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.

Can a pointer be null?

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.


4 Answers

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.

like image 124
Nicol Bolas Avatar answered Oct 20 '22 02:10

Nicol Bolas


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.

like image 45
Toby Speight Avatar answered Oct 20 '22 02:10

Toby Speight


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.

like image 38
David Thornley Avatar answered Oct 20 '22 03:10

David Thornley


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.

like image 33
Sneftel Avatar answered Oct 20 '22 01:10

Sneftel