regarding left shift and right shift operator

萝らか妹 提交于 2019-12-01 21:10:35

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:

  1. 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 int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned 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.

  2. 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.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!