void times(unsigned short int time)
{
hours=time>>11;
minutes=((time<<5)>>10);
}
Take the input time to be 24446
The output values are
hours = 11
minutes = 763
The expected values are
hours = 11
minutes = 59
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
intis wider thanshort. Ifunsigned intandunsigned shortare 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 thewhat-ifrule 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.
This piece of code seems to think that int is 16 bit and left shifting time would clear the top 5 bits.
Since you're most likely working in 32/64 bits, it doesn't happen if the value in time is a 16 bit value:
time >> 5 == (time << 5) >> 10
Try this:
minutes = (time >> 5) & 0x3F;
or
minutes = (time & 0x07FF) >> 5;
or
Declare time as unsigned short and cast to unsigned short after every shift operation since math is 32/64 bit.
24446 in binary is: 0101 1111 0111 1110
- Bits 0-4 - unknown
- Bits 5-10 minutes
- Bits 11-16 hours
It seems that size of 'int' for the platform you working on 32 bits. As far as processing is concerned assume that, First statement is dividing "time" by '11'. Second statement is multiplying "time" by 5 then dividing whole by 10. Answer of your question ends here.
If you add what time value actually contains(number of seconds/miliseconds/hours or something else) then you may get more help.
Edit: As @egur pointed out,you might be porting your code from 16 bit to 32/64 bit platform. A widely accepted C coding style to make the code portable is something like below:
make Typedef.h file and include it in every other C file,
//Typedef.h
typedef unsigned int U16
typedef signed int S16
typedef unsigned short U8
typedef signed short S8
:
:
//END
Use U16,U8 etc. while declaring variables.
Now when you move to larger bit processor say 32 bit,Change your Typedef.h to
//Typedef.h
typedef unsigned int U32
typedef signed int S32
typedef unsigned short U16
typedef signed short S16
No need to change anything in rest code.
edit2:
after seeing your edit:
((Time<<5)>>10) gives 111011 which means 59.
For 32 bit processors
((Time<<5)>>10) gives 0000 0010 1111 1011 which means 763.
来源:https://stackoverflow.com/questions/24080351/regarding-left-shift-and-right-shift-operator