OK let me explain in some detail what's going on. Any binary notation to clarify will be prefixed with 0b and the most significant bit on the left.
char c1 = 0xFF; // -1
char c1 is an eight-bit signed integer type, which is set to 0b11111111
For signed types such as int, short and char, the leftmost bit is used as the sign bit. In two's complement, the most common standard for storing signed types, any signed integer with all bits set is equal to -1.
int shifted = c1 << 8; //-256 (-1 * 256)
c1 is implicitly cast to a signed integer before the shift, so we have an int of -1 which is 0xffffffff
. The shift operator in C is a non-rotating shift, i.e. any bits shifted "from" outside the value will be set to zero. After the shift we have 0xffffff00
, which is equal to -256 in two's complement.
printf( "%d, %x\n", shifted, shifted );
int myInt;
myInt = 0xFFFFFFE2;
printf("%d\n",myInt);
You're reading a signed integer which is printed according to two's complement.
int i = 0xff ;
printf("%d\n", i<<2);
The initial i is equivalent to 0b11111111
, the sign bit not being set. After the shift we have 0b1111111100
, which is equal to 1020, again because of non-rotating shift. Hope that clarifies things a bit. If you want to do bit shifts and AND/OR logic you should typically use unsigned types as mentioned before.