Thursday, March 5, 2009

Bitshifting an array of u8's

I had an interesting problem come up the other day where we needed to bitshift an array by more than 8 bits. Basically, given an array, can you bitshift the entire thing? This doesn't make much sense with signed values, so be sure to use unsigned values.

The only real approach has to do with figuring out the real shift amount. If you are shifting across multiple bytes (say 48 bits to the left), then you need to jump ahead in the array to grab the bits and put those into the current set of bits. If you shift all of the current bits off, that isn't a problem; the bit just disappear.

So the code for this looks like the following. It's pretty simple code but there are a few edge cases. We need to be sure that we don't try to read beyond the end of the array and we also need to 0 out bytes that should no longer have values after the shift.


void ShiftLeft (unsigned char* array, int count, int NumBits)
{
int JumpGap = NumBits / 8;
assert (NumBits>0 && JumpGap < count);
NumBits = NumBits % 8;

count -= JumpGap;// stop slightly early.
for (int i=0; i<count; i++, array++)
{
*array <<= NumBits;
*array += (*(array+JumpGap+1)) >> 8-NumBits;
}
if (JumpGap < 1)
{
*array <<= NumBits;// shift the last char
array++;
}
else
{// fill the end with 0's. We've shifted too many bytes.
for (int i=0; i<JumpGap; i++)
{
*array = 0;
array++;
}
}
}

When testing this code, I had to output the bit state and the code for that looks like this:

void OutputBitstate (const unsigned char* array, int count)
{
for (int i=0; i<count; i++)
{
unsigned int value = array[i];
for (int j=0; j<sizeof (char)*8 ; j++) // show as bits
{
if (value & (1<<7))
cout << 1;
else
cout << 0;
value <<= 1;// shift the bits off the top.
}
cout << " ";
}
cout << endl;
}

No comments: