Spiros Bousbouras said:
So, although 0L has type long it is also a null pointer constant, yes?
To give another example 0 , 0L , 0u , 0llu are all arithmetic types
but they are also null pointer constants, yes? Is it ever possible for
a null pointer constant to have pointer type?
Don't get hung up on the name "null pointer constant". As Voltaire
famously said, the Holy Roman Empire was neither holy, nor Roman, nor
an empire; a null pointer constant is at least a constant, even though
it's not necessarily either a null pointer or a pointer. A null
pointer constant is defined by the standard's definition of the term:
An integer constant expression with the value 0, or such an
expression cast to type void *, is called a _null pointer
constant_. 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.
Only the first sentence is the definition of the term, so a literal 0
(or 0ULL, or '\0', or ('-'-'-') is a null pointer constant regardless
of the context in which it appears. The second sentence explains what
null pointer constants are good for: converting one to a pointer type
yields a null pointer.
The most important distinction to remember here, IMHO is that a "null
pointer constant" is a construct in C source code, whereas a "null
pointer" is a value that can occur only during program execution.
To answer your question, yes, (void*)0 is a null pointer constant.
Warning: extreme nit-picking follows.
If we take the wording of the standard painfully literally, (void*)0
is by definition a null pointer constant, but ((void*)0) is not. C99
6.5.1p5 defines the attributes of an unparenthesized expression that
are inherited by the corresponding parenthesized expression, namely
its type, its value, whether it's an lvalue, where it's a function
designator, and whether it's a void expression. This list doesn't
include whether it's a null pointer constant. So, strictly speaking,
((void*)0) isn't a null pointer constant. The macro NULL must expand
to a null pointer constant, but it can't expand to (void*)0 because
of 7.1.2p5:
Any definition of an object-like macro described in this clause
shall expand to code that is fully protected by parentheses where
necessary, so that it groups in an arbitrary expression as if it
were a single identifier.
(Note that both 0 and (0) are both null pointer constants, since both
are integer constant expressions.)
But most or all implementations rightly ignore this and treat
((void*)0) as a null pointer constant anyway, which was certainly the
intent. The solution is to clean up the wording of 6.5.1p5.
I was going to argue that (void*)0 is a null pointer constant but
doesn't necessarily yield a null pointer value when evaluated, but
fortunately that's not the case. (void*)0 is a null pointer constant,
which yields a null pointer when converted to a pointer type. If the
NPC itself is not converted (because it's already of type void*), the
standard doesn't actually say that it yields a null pointer. But
we're saved by the fact that 0 is also a null pointer constant, so
(void*)0, in addition to being a null pointer constant itself, is also
a null pointer constant converted to a pointer type.