This also applies to casting to intptr_t.
Not quite sure how that bears on the question of casting typed
pointers to void pointers, since intptr_t is neither. But anyway ...
Is there any rationale why
plain 0 is allowed for NULL?
Quoth the, er, um, Rationale:
NULL can be defined as any null pointer constant. Thus existing
code can retain definitions of NULL as 0 or 0L, but an
implementation may also choose to define it as (void*)0. This
latter form of definition is convenient on architectures where
sizeof(void*) does not equal the size of any integer type.
But it then goes on to say
It has never been wise to use NULL in place of an arbitrary
pointer as a function argument, however, since pointers to
different types need not be the same size.
From this, my guess is that prior to the Standard-ization of NULL
there were plenty of systems that provided their own NULL definitions.
Those definitions would not have been ((void*)0), since void* was not
part of the language as described in K&R, and many compilers would not
have been able to process it. So those implementations defined their
own NULL's as 0 or some close variant, and the Committee felt it would
be unwise to invalidate them and the programs that had grown up with
them. As the Rationale says elsewhere, "Existing code is important,
existing implementations are not."
I'm feeling tempted to define my own
macro for (void*)0 just to avoid the above pitfalls...
There's a fuzzy line between enhancement and obfuscation. If
you run across a line like
func(13.6, &a, &b, (void*)NULL);
you have to ask yourself whether it's more or less readable than
func(13.6, &a, &b, ALANKO);
Even then, you might find yourself needing to write
func(14.6, &a, &b, (struct goombah*)ALANKO);
.... and it doesn't seem to me you've gained a whole lot.