void times(unsigned short int time)
{
hours=time>>11;
minutes=((time<<5)>>10);
}
time to be 24446The output values are
The expected values are
What internal processing is going on in this code?
Binary of 24446 is 0101111101111110
Time>>11 gives 01011 which means 11.
((Time<<5)>>10) gives 111011 which means 59.
But what else is happening here?
What else is going on here?
If time is unsigned short, there is an important difference between
minutes=((time<<5)>>10);
and
unsigned short temp = time << 5;
minutes = temp >> 10;
In both expressions, time << 5 is computed as an int, because of integer promotion rules. [Notes 1 and 2].
In the first expression, this int result is then right-shifted by 10. In the second expression, the assignment to unsigned short temp narrows the result to a short, which is then right-shifted by 10.
So in the second expression, high-order bits are removed (by the cast to unsigned short), while in the first expression they won't be removed if int is wider than short.
There is another important caveat with the first expression. Since the integer promotions might change an unsigned short into an int, the intermediate value might be signed, in which case overflow would be possible if the left shift were large enough. (In this case, it isn't.) The right shift might then be applied to a negative number, the result is "implementation-defined"; many implementations define the behaviour of right-shift of a negative number as sign-extending the number. This can also lead to surprises.
Notes:
Assuming that int is wider than short. If unsigned int and unsigned short are the same width, no conversion will happen and you won't see the difference you describe. The "integer promotions" are described in §6.3.1.1/2 of the C standard (using the C11 draft):
If an
intcan represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to anint; otherwise, it is converted to anunsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
Integer promotion rules effectively make it impossible to do any arithmetic computation directly with a type smaller than int, although compilers may use the what-if rule to use sub-word opcodes. In that case, they have to produce the same result as would have been produced with the promoted values; that's easy for unsigned addition and multiplication, but trickier for shift.
The bitshift operators are an exception to the semantics of arithmetic operations. For most arithmetic operations, the C standard requires that "the usual arithmetic conversions" be applied before performing the operation. The usual arithmetic conversions, among other things, guarantee that the two operands have the same type, which will also be the type of the result. For bitshifts, the standard only requires that integer promotions be performed on both operands, and that the result will have the type of the left operand. That's because the shift operators are not symmetric. For almost all architectures, there is no valid right operand for a shift which will not fit in an unsigned char, and there is obviously no need for the types or even the signedness of the left and right operands to be the same.
In any event, as with all arithmetic operators, the integer promotions (at least) are going to be performed. So you will not see intermediate results narrower than an int.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With