I can't understand the line "The result of the shift has the same type as the thing that got shifted (after the integral promotions)" in the following extract from the C book by Mike Banahan (Section 2.8.2.3).
Importantly, the rules involving mixed types of operands do not apply to the shift operators. The result of the shift has the same type as the thing that got shifted (after the integral promotions), and depends on nothing else.
If something is already promoted to an integer (as required during shift operator use), then how can it be converted back to the same type as it originally had, unless of course it is on the right side of an assignment and is being assigned to a variable of the same type as it had before integer promotion? Further, what exactly does the line "the rules involving mixed types of operands do not apply to the shift operators" signify?
Please shed some light on both parts of the question. Thank you.
The following are screenshots from the book, relating to promotions during use of bit-wise operators and during mixed expressions in general, respectively.
It is pretty straight forward; the type of the result of a shift operation is the type of the LHS operand. For most binary operators, the result is based on both the LHS and RHS operands, but the shift operators are different.
unsigned char uc = 0x08;
unsigned short us = 0x0008;
unsigned int ui = 0x00000008;
unsigned long long ul = 0x0000000000000008;
(I'm assuming sizeof(unsigned int) == 4
for this answer. The details have to change if it is different, but the concepts remain unchanged.)
Now consider some expressions:
uc + uc;
Both types are converted to int
and the result is int
.
us + us;
Again, both types are converted to int
and the result is int
.
us + ui;
ui + us;
The value in us
is converted to unsigned int
and the result is unsigned int
(note that the previous values were converted to signed int
aka int
).
ui + ul;
ul + ui;
Both of these expressions convert ui
to an unsigned long long
and the result is unsigned long long
. Note that these expressions are symmetric; the type of the result (and, indeed, with the +
operator, the value of the result) does not depend on which value is on the LHS and which on the RHS of the operator.
So much for the ordinary operations; now what about shifts?
uc << uc;
The LHS is converted to int
by the usual arithmetic conversions and the result is an int
.
us << us;
This result is also an int
.
ui << ui;
This result is an unsigned int
.
ul << ul;
This result is an unsigned long long
. But what about mixing the types up?
uc << ul; // Result: int
ul << uc; // Result: unsigned long long
us << ui; // Result: int
ui << us; // Result: unsigned int
ui << ul; // Result: unsigned int
ul << ui; // Result: unsigned long long
The promoted type of the LHS operand controls the type of the result. For the types shorter than int
, the result is int
; for the other types, the type is the type of the LHS operand.
That's all your quote means.