Search code examples
ctype-conversionbitwise-operatorsinteger-promotion

Can you please explain this—"the rules involving mixed types of operands do not apply to the shift operators"


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.

enter image description here

enter image description here


Solution

  • 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.