Thread: Signed/Unsigned char issues

1. Signed/Unsigned char issues

Code:
```signed char n = -94;
unsigned char p;

p = (n >>3) | (n << (8-3));

putc(p);```
Signed char n is -94, which is 10100010
After doing a bit rotate, it should be 01010100, which is then put into Unsigned char p.

I am expecting the putc to be printing out 'T', which is 01010100 (decimal 84). However, it is printing an o with a carat above it, which the debug is showing as decimal 244, or 11110100.

What am I missing here?

2. What is 10100010 shifted left five times?
What is 10100010 shifted right three times?

Quzah.

3. Originally Posted by quzah
What is 10100010 shifted left five times?
What is 10100010 shifted right three times?

Quzah.
They are 01000000 and 00010100. Then they are OR'd together, which should produce 01010100, then that should be moved into p

4. Are you sure they aren't 01000000 and 11110100?

5. >> What am I missing here?

Remember: the result of a shift is an *int*. So what happens is the signed char is first converted to an int, and because of sign extension the most significant bits of the int are filled with ones (because the value is negative). When the value is shifted right all of these ones are of course shifted into the least significant byte. At any rate, you just need to cast the value to an unsigned type before shifting to get the correct results.

6. If it's signed, then it depends on how they feel like implementing it. It could be zeros, it could be the left most bit's value, depending on the direction you're shifting anyway. I find it easiest to just write a function to spit out what the bits look like, if what I'm shifting doesn't look like what I think it should.

Quzah.

7. Ah! Thanks guys. That would make sense. If the char is signed, and it's a negative number, then a bit shift converts the char to an int, and fills up the most significant byte with 1's, so that when shifting right, those 1's are pulled in.

Makes sense now, but I thought I was going crazy for a bit there. Thanks.

8. Not sure what the OP means by "bit rotate" which is slightly different from shifting.
Given "10100010" pattern, a bit rotate left puts the MSB into the LSB.
Remaining bits are shifted left resulting in "01000101" bit pattern.

9. Originally Posted by NewbGuy
Ah! Thanks guys. That would make sense. If the char is signed, and it's a negative number, then a bit shift converts the char to an int, and fills up the most significant byte with 1's, so that when shifting right, those 1's are pulled in.

Makes sense now, but I thought I was going crazy for a bit there. Thanks.
No, not quite. On my system, if I shift:
Code:
`10000000000000000000000000000000`
...which is a negative, to the right, I get something like:
Code:
`11111100000000000000000000000000`
1s are shifted in. Note what quzah said, since:

Originally Posted by C89
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity, 2 raised to the power E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined.
(Emphasis mine.)

10. well, just for interest i tried to cast n to the unsigned int, but it stil gives the value of 244..

Code:
```signed char n = -94;
unsigned char p;

p =   ((unsigned int)n >>3) | (n << (8-3)) ;

printf("%d", p);```
p is still 244... so how to make it 84?

11. You only cast one side.
The other side is still doing signed integer shifting.

12. Originally Posted by BlackOps
just for interest i tried to cast n to the unsigned int, but it stil gives the value of 244..
Cast to unsigned char. When you cast to unsigned int, you get a non-negative integer equal to UINT_MAX + 1 - 94.

13. If you know x86 assembly, this is the difference between SHR (shift right) and SAR (shift arithmetic right). If the number is treated as signed, then the sign bit is duplicated as the value shifts right.

It's almost never correct to apply shifts to signed quantities. Shifting implies that you are processing a quantity in a bitwise fashion. But the bits within a signed quantity have special meanings. If you are manipulating bits you should always be using unsigned types.

(I suppose you could be trying to use the trick where you shift right instead of dividing by a power of two. Don't use that trick. The compile IS smart enough to do that for you. If not, get a better compiler)

14. yes! casting to unsigned char helped, ok =)

15. Originally Posted by laserlight
Cast to unsigned char. When you cast to unsigned int, you get a non-negative integer equal to UINT_MAX + 1 - 94.
This is what I did and it worked. Thanks all. Learned a lot with this thread.

Popular pages Recent additions