From the C17 draft (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.67) 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.67)The macro
NULL
is defined in<stddef.h>
(and other headers) as a null pointer constant [...].
From this, it follows that the following are null pointer constants: 0
, 0UL
, (void *)0
, (void *)0UL
, NULL
.
It further follows that the following are null pointers: (int *)0
, (int *)0UL
, (int *)(void *)0
, (int *)(void *)0UL
, (int *)NULL
. Interestingly, none of these are "null pointer constants"; see here.
The following null pointer constants are null pointers (because void *
is a pointer type and 0
and 0UL
are null pointer constants): (void *)0
, (void *)0UL
. In this regard, according to the C17 draft (6.2.5 ¶19-20):
The
void
type comprises an empty set of values; it is an incomplete object type that cannot be completed.
[...]
A pointer type may be derived from a function type or an object type, called the referenced type. [...] A pointer type is a complete object type.
void
is not a pointer type itself, and it is an incomplete object type. But void *
is a pointer type.
But it seems that the following are null pointer constants which are not null pointers (because there is no cast to a pointer type): 0
, 0UL
, NULL
. (To be precise, while the standard only requires that NULL
be defined as "a null pointer constant", it would be permissible to define it as a null pointer constant which is also a null pointer. But it seems that the standard doesn't require NULL
to be defined in such a way that it is simultaneously a null pointer.)
Is every null pointer constant a null pointer? (Is NULL
really not a null pointer?)
Finally (and somewhat tongue-in-cheek): In case certain null pointer constants are not null pointers, would they technically be a kind of "non-null pointer"? (This wording appears in some places in the standard.) Note that linguistically we have a so-called bracketing paradox; we can read this as "[non-null] pointer" or "non-[null pointer]".
Is every null pointer constant a null pointer?
TL;DR: no.
As you have already observed, integer constant expressions with value 0 are null pointer constants, despite not having pointer type. You have also quoted the specification's definition of null pointer: "a null pointer constant [] converted to pointer type". That means that null pointer constants of this general form ...
(void *)(<integer constant expression with value 0>)
... satisfy the definition of "null pointer". The integer constant expression is a null pointer constant itself, so the cast makes the overall expression a null pointer (in addition to being a null pointer constant).
On the other hand, null pointer constants that take the form of integer constant expressions with value 0 do not satisfy the definition of "null pointer", and there is no other provision in the language spec that would make them null pointers. Examples: 0
, 0x00UL
, 1 + 2 + 3 - 6
.
it seems that the standard doesn't require NULL to be defined in such a way that it is simultaneously a null pointer.
Correct.
Is every null pointer constant a null pointer?
Definitely not (see above), but for most purposes, it does not matter.
(Is
NULL
really not a null pointer?)
It depends on your C implementation. The language spec allows either answer. In practice, it is a null pointer in most implementations you're likely to meet.
In case certain null pointer constants are not null pointers, would they technically be a kind of "non-null pointer"?
No. Null pointer constants that are not null pointers are not pointers at all. They are integers.