I need help solving this problem in my mind, so if anyone had a similar problem it would help me a lot.
signed char c=0x10;
printf("%x", c<<0x4|c>>0x4);
Why output is 101?
CodePudding user response:
In expressions with shift operators the integer promotions are applied to the each operand and in this particular case to the object c
.
From the C Standard (6.5.7 Bitwise shift operators)
3 The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand....
So after the integer promotions it will be represented like (provided that sizeof( int )
is equal to 4
)
00000010
This expression
c<<0x4
produces the following value
00000100
and this expression
c>>0x4
produces the following value
00000001
The bitwise operator | yields
00000100
|
00000001
========
00000101
The result is outputted without leading zeroes as
101
That is the function printf outputs the resulted value of the type int as an object of the type unsigned int because the resulted value can be represented in an object of the type unsigned int.
To get the expected by you result use the length modifier hh
as for example
printf("%#hhx", c<<0x4|c>>0x4);
In this case the program output will be
0x1
CodePudding user response:
signed char c=0x10;
printf("%x", c<<0x4|c>>0x4);
Why output is 101?
Because c<<4==0x100
and c>>4==0x01
.
ORing them together results in 0x101
Important here is that there is implicit type promotion to int
before applying the <<
operator.
If you expected to get the nibbles swapped, you need to add some masking:
(c&0x0F)<<4 | (c&0xF0)>>4
CodePudding user response:
In most expressions, a signed char
is automatically promoted to an int
, which is at least 16 bits. So c<<0x4
is evaluated with at least 16 bits of data; it does not lose the high bits as it would if the result were limited to eight bits.
So c << 0x4
shifts 0001 0000 by four bits, producing 0001 0000 0000. And c >> 0x4
of course produces 0001. ORing those together produces 0001 0000 0001, which is 10116.
You can remove the high bits in various ways. One is to explicitly convert the subexpression to the desired type: (signed char) (c << 0x4) | c >> 0x4
. Note this has a problem in that the conversion of an out-of-range value to a signed type is implementation-defined. It is usually preferable to use unsigned types when working with bits in this way, as then the results are fully defined by the C standard.
Another method is to use AND with a “mask” to select the desired bits: (c << 0x4 | c >> 0x4) & 0xFF
.