Keith Thompson said:
If the implementation plays tricks like that, it's not very meaningful
to say that NULL is defined in any particular way. There might be
something in some file that looks like a macro definition, but it's
not really *the* definition of NULL.
There is some merit in what you say. Depending on special purpose
processing like this makes it difficult to talk about program
elements with our usual vocabulary, because the meanings of the
words have gotten rather slippery.
However, I don't think it diminishes my basic point, which is that we
can't conclude a priori that the #define line above "can't work". For
example, suppose the system header file contained these lines:
#pragma object_macro NULL
...
#define NULL (void*)0
with the obvious meaning for the #pragma line. I think most
people wouldn't be especially bothered by an implementation
that defined NULL in this way; surprised perhaps, but not
especially bothered. Furthmore, in some sense this definition
reflects more directly what the Standard requires of NULL -
namely, that it is an object macro, and that it produces a null
pointer constant.
To restate my basic point: we can't conclude a priori that
a #define line
#define NULL (void*)0
has problems; it's allowed, and it can be conformant. And
I would now add: in ways that aren't too much of a stretch.
I'm not convinced that such tricks are legal anyway. Can you cite a
clause of the standard that says they are?
Basically 7.1.2, especially paragraph 1. System headers don't have
to be files in the ordinary sense, and the wording in the Standard
says that the "contents [of the header] are made available by
the #include preprocessing directive." The contents are "made
available", but there don't seem to be any restrictions on
how that's done, or what form the "contents" take. Also I think
it's fairly commonly accepted that an implementation is allowed
to treat system functions in special ways, eg, inline data movement
for 'memcpy()'; I guess this freedom is generally allowed under
the "as if" rule, which seems to apply equally to NULL as it does
to memcpy(), etc.