Post by Wojtek LerchPost by Tim Rentsch[...] And the Standard's does not promise that *all* unsigned
representations of an unsigned value less than or equal to INT_MAX
are also valid signed representations.
I agree that what you say matches the letter of the Standard's
rules here. But surely what was intended is for the relationship
to be symmetric, wouldn't you agree?
No, my understanding has been that the asymmetry was intentional. I
don't remember if it was because of some explanation I read here or
purely a guess; but the example that I've had in my head is a
hypothetical processor whose unsigned arithmetic completely ignores
the sign bit of operands and produce results with the sign bit unset,
but bitwise operations work on all the bits. An implementation for
such hardware might prefer to avoid having to generate an extra opcode
to clear the sign bit whenever it stores the result of an unsigned
bitwise operation, so it would treat all possible bit patterns as
valid unsigned representations regardless of the state of the sign
bit. (Of course, the sign bit would be considered a padding bit by
C.) In other words, any unsigned value would have two representation
in this implementation -- one identical to the signed representation,
and the other one with the sign bit set to 1.
Your example looks like it is on point. I'm not sure though how
likely it is, and I don't remember ever seeing or hearing it
before.
Looking at the history reinforces my view that a symmetric
relationship is what was intended. In C90 there was no text
corresponding to 6.2.6.2 p2, and the only other pertinent passage
(6.2.5 p9, which was present in C90 but the numbering scheme was
a bit different) expresses a symmetric relationship. If that
were meant to be changed, from symmetric to non-symmetric, in
C99, that would constitute significant change between the two
versions. (I say it is significant because behavior that
previously was defined in C90 could become undefined in C99.)
Any such change I would normally expect would be mentioned in
the Rationale document, but AFAICT no such mention occurs.
Post by Wojtek LerchPost by Tim RentschConsidering other passages
in the Standard where signed and unsigned types are guaranteed to
be interchangeable if the value is representable in both types,
Yes, that's an interesting inconsistency, but off the top of my head I
don't recall any such passages in the normative text -- aren't they
all footnotes?
Actually I had forgotten about the footnotes. I was thinking
of the requirements for what types are allowed for certain
function calls - 6.5.2.2 p6, and what is more or less the
same thing for va_arg() in <stdarg.h>. Both of these are in
normative text. To keep a certain interested reader happy,
let me quote a portion of 6.5.2.2 p6:
If the function is defined with a type that does not include
a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after
promotion, the behavior is undefined, except for the
following cases:
- one promoted type is a signed integer type, the other
promoted type is the corresponding unsigned integer
type, and the value is representable in both types;
- [..the other case is void * and character pointers..]
Post by Wojtek LerchPost by Tim Rentschit seems clear that the phrasing used in 6.2.6.2 is just an
oversight and was meant to imply guarantees in both directions.
I agree that there seems to be an oversight but it's not clear to me
where the mistake is. It doesn't seem totally implausible to me that
6.2.6.2 was written carefully, to allow implementations like the one I
described above, but then the footnotes about interchangeability were
written without enough thought being given to those strange
implementations.
I agree with you: it isn't totally implausible. Moreover the
footnotes were written before (I believe) in C90, but the
text in question in 6.2.6.2 was added in C99.
On the other hand, the normative passages I mentioned above
were also added in C99. Draw your own conclusions.