* James Kanze:
That explains why it works in practice. But a compiler is
allowed to implement variable args in such a way that it does
type checking. The normal situation in the case of va_arg is
that if the types mismatch, then in general, the code has
undefined behavior, according to the standard.
Anyway, as Jack Klein points out, it is undefined behavior in
C90, and thus in C++ today, but the C99 standard explicitly
added two exceptions: one for signed and unsigned, when the
value is in the common range, and one for void* and char*, and
presumably, the next version of the C++ standard will be based
on this. If we assume (which seems safe) 1) that it does work
with all current implementations, and 2) that it will be
required to work in the next version of the standard, I'd say
that it's a pretty safe bet. Like long long, for example.
I'm not sure I like having the exceptions, since it makes
implementing a checking implementation more difficult.
Considering how old these languages are, the non-existence of such
checking implementation is pretty significant. ;-)
I think we must distinguish clearly between explicit UB, where the
standard explicitly and intentionally gives the implementation the
widest latitude possible in how to handle things (or not), and implicit
UB, where the standard is silent, which only with contorted logic can be
regarded as intentional: more likely an unintentional omission or simply
not regarded as practically relevant enough to waste time on specifying.
Regarding /implicit/ purely formal UB it's possible that it is, but
proving that is like proving a negative: one must prove conclusively
that there's nothing that directly or by implication makes it defined,
and anyway it is, as you hint, practically speaking irrelevant because
of C99 and C++0x -- the world moves on...
Integral representation is irrelevant to the question.
On the contrary, it's very relevant, because the C++ standard is not an
arbitrary collection of rules: it's a set of rules intended to specify a
practically useful language, capturing existing practice.
So that when you don't have a directly applicable formal rule at hand,
considering the practice, here the representation, can tell you what the
practical conclusion must be, without recourse to the inaccessible or
very difficult to find or very difficult to reason out formal.
Considering the integral representation thus (1) tells a developer what
the practical answer is for practical coding, and (2) tells a language
lawyer what the standard should be if it isn't already (and hence, a
possible improvement). And for (2) one doesn't even need to know
whether the formal already covers this. All one does need to know is
that it's so darn difficult to find, that explicit language that
formalizes the practice would be a great improvement.
Just
because an implementation uses the same representation for long
and int, you can't pass an int to a "%d"---the results are
undefined behavior, and not implementation defined.
Well, first, I can, and moreover anyone can, with in practice well
defined result, and second, you haven't proved that it's implicit UB or
explicit UB. The latter could be possible in a Usenet discussion, but I
doubt that here is explicit UB. The former, proving implicit UB, well
then I think we need to stock up with beer and foodstuff...
Arguments to a var args parameter always undergo integral
promotion. (Or is this only so trivially obvious to me because
I wrote a lot of C back in the days when it was K&R C, and you
didn't have prototypes?)
I just mentioned it because possibly it wasn't obvious to the OP.
Cheers,
- Alf