This is called "usual arithmetic conversions" by the standard and applies whenever two different integer types occur as operands of the same operator.
In essence what is does
- if the types have different width (more precisely what the standard
calls conversion rank) then it converts to the wider type
- if both types are of same width, besides really weird architectures,
the unsigned of them wins
Signed to unsigned conversion of the value -1
with whatever type always results in the highest representable value of the unsigned type.
For line (1) the outcome depends on how wide long
and int
are. If int
is narrower than long
, all unsigned
values fit in long
, and so the conversion stops at long
for the RHS. The outcome then is "A". If they are of same width, the conversion continues to unsigned long
for both sides and the outcome is "B".
For your special case for short
there is also a feature called "integer promotions" that promotes all types that are narrower than int
to int
. In your lines 3 and 4 you'd have that the expressions on the LHS are first converted to int
, which keeps the value unchanged, and then for (3) to unsigned int
and for (4) to unsigned long
.
According to that my platform (linux, gcc) correctly prints "ADFH" with your code.
The result "BDEH" would occur on a platform that first has long
and int
of the same width and has the range of unsigned
covered by the range of int
, that is which for unsigned
just ignores the sign bit of int
. I didn't know that such platforms still exist.
Some years I wrote a blog post on the anatomy of integer types, which should still be valid.