简体   繁体   中英

C left shift and assignment

Please check the below pieced of code and let me know why this is not giving desired result.

#include <stdio.h>
int main()
{
  unsigned short y=0;
  unsigned char x=0xe0; //binary - 1110 0000
  unsigned char z=3;

  y = (x<< z);
  printf("\n y value is %x\n",y);
  return 0;
}

I am expecting y should print 0x00 but it is printing 0x0700. Could you let me know how left shift and assignment operation working here ?

Thanks

By specification the left operand of the bitwise shift operator undergoes integer promotion.

So:

 y = (x<< z);

is here equivalent to:

 y = ((int) x << z);

The result of the << expression is of the type of the promoted left operand, ie, int and it is converted to unsigned short during assignment.

The operation promotes your bytes to ints. So its doing a left shift on ints

The reason is integer promotion of x .

C11: 6.5.7 Bitwise shift operators (p3):

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.

You have to write

y = ( unsigned char )(x<< z);

The problem is that the integer promotion is applied to operands of operator <<. That is integral data that has rank less than the rank of type int are implicitly converted to type int .

So in this expression

x<< z

x will have the representation like

00 00 00 E0

and after the operation the result will look as

00 00 07 00

that is the three set bits will be shifted left and will occupy the next byte of the object of type int . Wneh the result is assigned to y that has type insigned short the two lower bytes of the result are assigned to y and y will be equal to 0x0700 .

In case of shift operator integer promotion is performed on each of the operands.

in your case x and z are converted to int and the result is converted back to short.

please see the relevant section from spec below.

6.5.7 Bitwise shift operators

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.

What compiler did is very natural.

You tried to put result in a lager space, so the operator did its work until the space allows to do it, otherwise you'd say explicitly the opposite: 0xff & mask or (unsigned char) . That's reflected in the language specification.

You should to know what you are doing, if you expected growing your value with shifting left that was okay to have unsigned short , but what did you wonder with 0x700 then?

If you wanted to make a sort of filtering - why didn't you use unsigned char which fits the best? Cause short is obviously outbound your filtering scenario (of course you'd like to save the space and write all-in-one line, but be careful).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM