That's simply not true. There is the rule, that NULL must be equal to (void *)0. I had also several discussions about that topic, but it's part of at least C99 and C11.
Yes, (void * )0 gives a null pointer. I mentioned that. However, that doesn't mean all the bits of a null pointer are required to be all 0. The actual machine representation of a null pointer is implementation-defined. The only requirement C99 places on the actual value of a null pointer is that it compares unequal to a pointer to any object or function, and any two null pointers compare equal. See section 6.3.2.3 paragraphs 3 and 4:
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.
Conversion of a null pointer to another pointer type
yields a null pointer of that type. Any two null pointers
shall compare equal.
If you do this:
int pv = 0;
char * p = (char *)pv;
you are not guaranteed to have p set to a null pointer, because the zero you are casting and assigning is not an integer constant zero. The behavior is implementation-defined, as is going the other way. Section 6.3.2.3 paragraphs 5 and 6:
An integer may be converted to any pointer type. Except
as previously specified, the result is implementation-defined,
might not be correctly aligned, might not point to an entity
of the referenced type, and might be a trap representation.
Any pointer type may be converted to an integer type. Except
as previously specified, the result is implementation-defined.
If the result cannot be represented in the integer type, the
behavior is undefined. The result need not be in the range of
values of any integer type.