[comp.lang.c] bit mover

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (03/15/91)

In article <788@llnl.LLNL.GOV>, handeli@ocfmail.ocf.llnl.gov writes:
> I need a C function which can move arbitrary bits around from one
> memory location to another with a bit offset of anything.  For
> example, the call might look like

> movebits(a1,ioff1,a2,ioff2,nbits)

This really belongs in a C group.  I have cross-posted to comp.lang.c
and am redirecting followups there.

I am assuming that the bits in a byte are taken LSB-first, so that an
offset of 9, for example, skips the first byte and the LSB of the
second byte.  To switch this, fiddle with some of the shift operations.

Warning: untested.  Assumes that the number of bits in an unsigned int
is no less than one less than twice the number of bits in an unsigned
char (most machines will have no trouble with this restraint).
Optimization possibilities abound.

#define CHAR_BITS 8 /* or whatever: # of bits in unsigned char */

movebits(a1,ioff1,a2,ioff2,nbits)
unsigned char *a1; /* from */
unsigned int ioff1;
unsigned char *a2; /* to */
unsigned int ioff2;
unsigned int nbits;
{
 unsigned int buf;
 unsigned char mask;
 int have;

 if (nbits < 1) return; /* careful: don't read *a1 in this case */
 a1 += ioff1 / CHAR_BITS;
 ioff1 %= CHAR_BITS;
 a2 += ioff2 / CHAR_BITS;
 ioff2 %= CHAR_BITS;
 buf = *a1++;
 have = CHAR_BITS - ioff1;
 buf >>= ioff1;
 while (nbits > 0)
  { if ((have < CHAR_BITS) && (nbits > have))
     { buf |= *a1++ << have;
       have += CHAR_BITS;
     }
    if (ioff2+nbits < CHAR_BITS)
     { mask = ((1 << nbits) - 1) << ioff2;
     }
    else
     { mask = (~0) << ioff2;
     }
    *a2 = (*a2 & ~mask) | ((buf << ioff2) & mask);
    a2 ++;
    buf >>= CHAR_BITS - ioff2;
    have -= CHAR_BITS - ioff2;
    nbits -= CHAR_BITS - ioff2;
    ioff2 = 0;
  }
}

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu