I need help solving this problem in my mind, so if anyone had a similar problem it would help me.
Here's my code:
char c=0xAB;
printf("01:%x\n", c<<2);
printf("02:%x\n", c<<=2);
printf("03:%x\n", c<<=2);
Why the program prints:
01:fffffeac
02:ffffffac
03:ffffffb0
What I expected to print, that is, what I got on paper is:
01:fffffeac
02:fffffeac
03:fffffab0
I obviously realized I didn't know what the operator <<=
was doing, I thought c = c << 2
.
If anyone can clarify this, I would be grateful.
CodePudding user response:
You're correct in thinking that
c <<= 2
is equivalent to
c = c << 2
But you have to remember that c
is a single byte (on almost all systems), it can only contain eight bits, while a value like 0xeac
requires 12 bits.
When the value 0xeac
is assigned back to c
then the value will be truncated and the top bits will simply be ignored, leaving you with 0xac
(which when promoted to an int
becomes 0xffffffac
).
CodePudding user response:
<<=
means shift and assign. It's the compound assignment version of c = c << 2;
.
There's several problems here:
char c=0xAB;
is not guaranteed to give a positive result, sincechar
could be an 8 bit signed type. See Is char signed or unsigned by default?. In which case0xAB
will get translated to a negative number in an implementation-defined way. Avoid this bug by always usinguint8_t
when dealing with raw binary bytes.c<<2
is subject to Implicit type promotion rules - specificallyc
will get promoted to a signedint
. If the previous issue occured where yourchar
got a negative value,c
now holds a negativeint
.Left-shifting negative values in C invokes undefined behavior - it is always a bug. Shifting signed operands in general is almost never correct.
%x
isn't a suitable format specifier to print theint
you ended up with, nor is it suitable forchar
.
As for how to fix the code, it depends on what you wish to achieve. It's recommended to cast to uint32
before shifting.