Bit shift and pointer oddities in C, looking for explanations
I discovered something odd that I can't explain. If someone here can see what or why this is happening I'd like to know. What I'm doing is taking an unsigned short containing 12 bits aligned high like this:
1111 1111 1111 0000
I then want to shif the bits so that each byte in the short hold 7bits with the MSB as a pad. The result on what's presented above should look like this:
0111 1111 0111 1100
What I have done is this:
unsigned short buf = 0xfff;
//align high
buf <<= 4;
buf >>= 1;
*((char*)&buf) >>= 1;
This gives me something like looks like it's co开发者_JS百科rrect but the result of the last shift leaves the bit set like this:
0111 1111 1111 1100
Very odd. If I use an unsigned char as a temporary storage and shift that then it works, like this:
unsigned short buf = 0xfff;
buf <<= 4;
buf >>= 1;
tmp = *((char*)&buf);
*((char*)&buf) = tmp >> 1;
The result of this is:
0111 1111 0111 1100
Any ideas what is going on here?
Yes, it looks like char
is signed on your platform. If you did *((unsigned char*)&buf) >>= 1
, it would work.
Lets break this down. I'll assume that your compiler thinks of short as a 16-bits of memory.
unsigned short buf = 0xfff;
//align high
buf <<= 4;
is equivalent to:
unsigned short buf = 0xfff0;
... and
buf >>= 1;
should result in buf having the value 0x7ff8 (i.e. th bits shifted to the right by one bit). Now for your fancy line:
*((char*)&buf) >>= 1;
lots going on here... first the left hand side needs to be resolved. What you're saying is take buf and treat it as a pointer to 8-bits of memory (as opposed to it's natural 16-bits). Which of the two bytes that buf originally referred to relies on knowning what your memory endian-ness is (if it's big-endian buf points to 0x7f, if it's little-endian buf points to 0xf8). I'll assume you're on an Intel box, which means its little endian, and now buff points to 0xf8. Your statement then says assign to that byte, the value at that byte shifted (and sign extended since char is signed) to the right by one, or 0xfc. The other byte will remain unchanged. If you want no sign extension, chast buf to a (unsigned char *).
精彩评论