Keith Thompson said:
Actually, we aren't in agreement. I think the issue is (reasonably)
clear-cut.
I don't see any inconsistency between saying the issue is reasonably
clear-cut and saying the issue is not clear cut. There's a difference
in degree between the two statements, but they aren't inconsistent.
So I'm not sure that I can agree that we aren't in agreement.
Agreed. However, there are cases where the standard gives explicit
permission to do something in an implementation-defined way, such as
the declaration of main(). The fact that it doesn't do so here is,
IMHO, significant.
Saying you believe it's significant isn't really a very convincing
argument, is it?
More specifically, look at the wording of 5.1.2.2.1, where 'main' is
specified. Clearly paragraph 1 intends to give a precise
specification of 'main'; in particular, the word "shall" is used.
The wording used in 6.3.2.3 p3 is quite different. The analogy
just doesn't seem strong enough to be very convincing.
Since there's a clear and unambiguous interpretation assuming the
definition is exhaustive, I believe that's the best interpretation.
If you want to believe that, it's ok with me. But your statement
doesn't offer me any reason why I should believe it.
Furthermore, there's an obvious reason not to believe it, which is
that interpreted as an exhaustive definition, the given wording is
clearly incomplete since it doesn't cover things like '((void*)0)'.
The standard doesn't give explicit permission for other forms of null
pointer constant. Using (void*)42 in a context that requires a null
pointer constant is a constraint violation. An implementation that
doesn't issue a diagnostic for such a use is non-conforming.
Saying an implementation that doesn't issue a diagnostic for such a
use must be non-conforming is predicated on the assumption that
implementation-defined null pointer constants aren't allowed. It's
circular reasoning.
On the other hand, an implementation certainly is free to choose a
representation for pointers where any address under, say, 100 is to be
interpreted as a null pointer. On such an implementation, it would be
perfectly reasonable for '(void*)42' to be allowed as a null pointer
constant.
Similarly, the standard doesn't give permission for other forms of
integer constants. An implementation can accept 0b11001001 as a
binary constant as a language extension, but it must issue a
diagnostic for any such constant in conforming mode.
Not the same thing at all. The form of integer constants is specified
by syntax rules; these rules have a precise and exact meaning. I
don't have a reference handy, but I believe there is a statement in
the Standard to the effect that a syntax violation must result in a
diagnostic. Certainly using an implementation-defined null pointer
constant *might* result in a diagnostic being issued, but I don't know
of any provision that *requires* one.
The term "implementation-defined" doesn't just mean that the
implementation gets to make a choice; it also means it has to document
that choice. If the standard merely said that NULL expands to a null
pointer constant, an implementation wouldn't be required to document
what it actually expands to. This would be no great loss, since code
shouldn't depend on the choice, but I believe the intent is that (a)
an implementation can choose any valid null pointer constant as the
expansion of NULL, and (b) it must document what choice it makes.
That's a plausible interpretation. However, that interpretation seems
better expressed by saying, eg, "NULL expands to a null pointer
constant; the choice of which null pointer constant is implementation
defined." You haven't really given any kind of convincing reason,
merely stated that you believe that's the intent. In the absence of
any such reason, allowing NULL to define an implementation-defined
null pointer constant seems like a better fit to the existing
language, because otherwise that language would probably have been
rewritten to better express the intent you suggest.
It wouldn't make sense to use the phrase "implementation defined" only
in a footnote.
I agree that it's better to put the "implementation defined" phrase
in the main text, in either interpretation; as mentioned above.
I believe the glitch in 6.3.2.3p3, which implies that (void*)0 is a
null pointer constant but ((void*)0) isn't, is simply an oversight. I
suspect the authors of the standard just assumed that an expression in
parentheses is equivalent to the expression without parentheses -- and
of course enclosing macro definitions in parentheses is almost always
a good idea. Implementations actually conform to the intent of the
standard in this case, rather than to the literal wording. I wouldn't
infer anything significant from this (though I'd certainly like to see
this corrected.)
A small correction - implementations conform to what *you presume* the
intent of the standard is. If implementation-defined null pointer
constants are allowed, then they may be conforming to the actual
standard and not just to the intent.
If your suspicion about simply forgetting about enclosing parentheses
were right, then other more complicated forms of "null pointer
constants" shouldn't work. Have you tried any of these? If not
you may be surprised by what you find.
I disagree. I find it much simpler to assume that the definition of
"null pointer constant" means exactly what it says, modulo the
parentheses glitch. The intent of the phrase "implementation-defined
null pointer constant" in 7.17p3 is quite clear given this
interpretation; there's no need to invent the idea of additional
implementation-defined *forms* of null pointer constant. There's also
no advantage in doing so; we have more than enough null pointer
constants already without allowing implementations to invent their
own.
If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?
Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.