Shift bit and weirdness pointers in C looking for an explanation

I found something strange that I cannot explain. If anyone here can see what and why this is happening, I would like to know. What I am doing is take an unsigned short containing 12 bits, aligned in height, like this:

1111 1111 1111 0000

Then I want to compress the beats so that each byte in a short hold of 7 bits with the MSB as the pad. The result shown above should look like this:

0111 1111 0111 1100

I did the following:

unsigned short buf = 0xfff;
//align high
buf <<= 4;

buf >>= 1;
*((char*)&buf) >>= 1;

      

This gives me something that looks like the correct image, but the result of the last change leaves the bit like this:

0111 1111 1111 1100

Very strange. If I use unsigned char as temporary storage and shift that then works like so:

unsigned short buf = 0xfff;
buf <<= 4;

buf >>= 1;
tmp = *((char*)&buf);
*((char*)&buf) = tmp >> 1;

      

Result:

0111 1111 0111 1100

Any ideas what's going on here?

+2


a source to share


2 answers


Yes, it looks like it's char

signed on your platform. If you followed *((unsigned char*)&buf) >>= 1

, it will work.



+4


a source


Let's break it down. I am assuming your compiler considers it short as 16-bit memory.

unsigned short buf = 0xfff; 
//align high 
buf <<= 4; 

      

equivalent to:

unsigned short buf = 0xfff0;

      

... and



buf >>= 1; 

      

should cause buf to be 0x7ff8 (i.e. a bit shifted right one bit). Now for your fancy line:

*((char*)&buf) >>= 1; 

      

lots go here ... first you need to solve the left side. What you say is taking buf and treating it as a pointer to 8 bits of memory (as opposed to natural 16 bits). Which of the two bytes initially referring to buf depends on what the endpoint of your memory means (if that big-endian buf points to 0x7f, if that small-value buf points to 0xf8). I assume you are on an Intel box, which means its little endian, and now buff points to 0xf8. Then, in your statement, you assign that byte, the value in that byte is shifted (and sign extended since the char was signed) to the right by one or 0xfc. The other byte will remain unchanged. If you don't want sign expansion, chast buf to (unsigned char *).

+1


a source







All Articles