astrachan
astrachan

Reputation: 9

Right bit-shift adds 1 to start of unsigned int in C

I'm attempting to shift a 16 bit address to get a set ID for a cache simulator in C, but when I try and bit shift right I get an extra 1 stuck onto my number.

I have the number 0010100010011001. I then shift to the left 3 digits to get 0100010011001000. So far so good. However, I then try to shift to the right 6 digits and end up with 0000010100010011 instead of 0000000100010011. All of my ints are unsigned, and it only adds one 1 when I try and shift.

My code to try and shift is the following. In my example, tag_size is 3 and b is 6.

    unsigned int temp = addr << tag_size;
    unsigned int temp1 = temp >> b;
    unsigned int setid = temp1 >> tag_size;

Upvotes: 0

Views: 434

Answers (2)

Doug Currie
Doug Currie

Reputation: 41180

You should use a mask and select the bits you are interested in; for example:

unsigned int temp = (addr << tag_size) & 0xffffu; // keep 16 low bits
unsigned int temp1 = temp >> b;
unsigned int setid = temp1 >> tag_size;

If I understand what you are after, the same thing can be accomplished with

unsigned int temp = addr & (0xffffu >> tag_size); // keep 16 low bits
unsigned int setid = temp >> b;

or

unsigned int temp = (addr << tag_size) & 0xffffu; // keep 16 low bits
unsigned int setid = temp >> (b + tag_size);

This makes the code independent of unsigned int size, which C guarantees is at least 16 bits.

Upvotes: 0

liamcomp
liamcomp

Reputation: 386

16 bit ints are not common these day. You could try defining the variable as a short which is commonly 16 bits. It all depends on the machine you are using. You could also use a uint16 if you are looking for a 16 bit integer.

It looks like the problem could be because the unsigned int you are using is not actually 16 bits as Christian Gibbons mentioned in a comment. When you shift 0010100010011001 to the left 3 digits you end up with 10100010011001000, with the left most 1 not being removed as you would expect in a 16 bit integer then when you shift right again you get the added 1 you were not expecting.

You could change your code to this and it should work as you originally expected:

uint16_t temp = addr << tag_size;
uint16_t temp1 = temp >> b;
uint16_t setid = temp1 >> tag_size;

Upvotes: 1

Related Questions