Why are NULL pointers defined differently in C and C++?
Back in C++03, a null pointer was defined by the ISO specification (§4.10/1) as
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
This is why in C++ you can write
int* ptr = 0;
In C, this rule is similar, but is a bit different (§6.3.2.3/3):
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
Consequently, both
int* ptr = 0;
and
int* ptr = (void *)0
are legal. However, my guess is that the void*
cast is here so that statements like
int x = NULL;
produce a compiler warning on most systems. In C++, this wouldn't be legal because you can't implicitly convert a void*
to another pointer type implicitly without a cast. For example, this is illegal:
int* ptr = (void*)0; // Legal C, illegal C++
However, this leads to issues because the code
int x = NULL;
is legal C++. Because of this and the ensuing confusion (and another case, shown later), since C++11, there is a keyword nullptr
representing a null pointer:
int* ptr = nullptr;
This doesn't have any of the above problems.
The other advantage of nullptr
over 0 is that it plays better with the C++ type system. For example, suppose I have these two functions:
void DoSomething(int x);
void DoSomething(char* x);
If I call
DoSomething(NULL);
It's equivalent to
DoSomething(0);
which calls DoSomething(int)
instead of the expected DoSomething(char*)
. However, with nullptr
, I could write
DoSomething(nullptr);
And it will call the DoSomething(char*)
function as expected.
Similarly, suppose that I have a vector<Object*>
and want to set each element to be a null pointer. Using the std::fill
algorithm, I might try writing
std::fill(v.begin(), v.end(), NULL);
However, this doesn't compile, because the template system treats NULL
as an int
and not a pointer. To fix this, I would have to write
std::fill(v.begin(), v.end(), (Object*)NULL);
This is ugly and somewhat defeats the purpose of the template system. To fix this, I can use nullptr
:
std::fill(v.begin(), v.end(), nullptr);
And since nullptr
is known to have a type corresponding to a null pointer (specifically, std::nullptr_t
), this will compile correctly.
Hope this helps!
Why is C++'s NULL typically an integer literal rather than a pointer like in C?
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.
Do all null pointers point to the same block of memory?
Let’s start with the definition of the NULL
pointer.
6.3.2.3 PointersC 2011 Online Draft
...
3 An integer constant expression with the value 0, or such an expression cast to typevoid *
, is called a null pointer constant.66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
4 Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
66) The macroNULL
is defined in<stddef.h>
(and other headers) as a null pointer constant; see 7.19.
So, a null pointer does not necessarily mean address 0
, it just means “whatever value the underlying system uses to indicate an invalid address” - think of it as a well-defined “nowhere”. It could be 0x00000000
, it could be 0xFFFFFFFF
, it could be 0xDEADBEEF
, or anything else.
As far as your source code is concerned, NULL
is always zero-valued, so you can test for NULL
pointers like
int *ptr = NULL;
...
if ( ptr )
// ptr is not NULL, do something with it
else
// ptr is NULL
Two null pointers will evaluate to the same value, modulo any differences in type representation (different pointer types may have different size and alignment requirements).
Are these null pointers, or are they pointers to address 0?
p1
and p2
are null pointers; p3
is implementation defined,
and may be something else. (A comma operator cannot be part of
a constant expression. And the mapping of a non-constant
integral value 0 to a pointer is implementation defined.) C is
identical to C++ here.
p8
and p9
are both null pointers in C++, but not in C.
With regards to your comment on static_zero_2
, there is no
requirement in either language that a literal zero be present,
anywhere. g++ defines NULL
as the compiler built-in __null
,
for example, and you can use (1 - 1)
, or '\0'
, or any other
constant expression evaluating to 0.
Is NULL always zero in C?
I'm assuming you mean the null pointer. It is guaranteed to compare equal to 0
.1 But it doesn't have to be represented with all-zero bits.2
See also the comp.lang.c FAQ on null pointers.
- See C99, 6.3.2.3.
- There's no explicit claim; but see the footnote for C99, 7.20.3 (thanks to @birryree in the comments).
NULL vs nullptr (Why was it replaced?)
nullptr
has type std::nullptr_t
. It's implicitly convertible to any pointer type. Thus, it'll match std::nullptr_t
or pointer types in overload resolution, but not other types such as int
.
0
(aka. C's NULL bridged over into C++) could cause ambiguity in overloaded function resolution, among other things:
f(int);
f(foo *);
(Thanks to Caleth pointing this out in the comments.)
how to distinguish between 0 and NULL in C
There is a confusion between testing if the pointer to struct node
passed to the function is a null pointer and the value of the integer data
member of the nodes in the list it points to.
NULL
is used in C as a macro to express a null pointer constant. It is used to test for null pointers. 0
is also a null pointer constant in a pointer context. Unlike in SQL, there is no concept of a null value representing no value in C for numeric values.
Here is a modified version of your code:
void ecrire(struct node *p) {
if (p == NULL) { // if the node pointer is NULL it means list is empty
printf("no items!\n");
return;
}
struct node *temp = p;
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
How is NULL different from 0 in C?
To the compiler, NULL
is indistinguishable from 0
when used as a pointer. The standard actually defines 0
to be a null pointer value, and the standard library just introduces a convenient macro NULL
defined to a null pointer value (usually 0
or ((void*)0)
), so that you can use it in code for better readability and expressing intent. But there's nothing special about NULL
itself; it's the 0
that is relevant.
Related Topics
Unit Testing for C++ Code - Tools and Methodology
How to Use Boost Bind with a Member Function
C/C++ Header and Implementation Files: How Do They Work
Is the Pass-By-Value-And-Then-Move Construct a Bad Idiom
When and How to Use Exception Handling
Std::Shared_Ptr Thread Safety Explained
Static Variables in an Inlined Function
Why Can't Static_Cast Be Used to Down-Cast When Virtual Inheritance Is Involved
Difference in Performance Between Msvc and Gcc for Highly Optimized Matrix Multplication Code
Seeking and Reading Large Files in a Linux C++ Application
How to Get Memory Usage Under Windows in C++