Hello,
I'm trying to write a function in a similar vein to the standard C function memcpy, only this one copies individual bits from one place to another. The source and the destination could be aligned/unaligned, so I'm doing the old heave-ho (shifting and masking).
It's appears to be so close to being correct that I've spent hours today trying to figure out what the problem is with it. As I don't fancy going blind, I'm posting it so some fresh minds can take a look and probably find the issue straight away.
My logic in this function is thus:-
1. Use a particular ......../mask combination for the first destination byte
2. Use a particular ......../mask combination for successive destination bytes
3. Use a particular ......../mask combination for the last destination byte
This should ensure that however the source and destination bits are aligned, one will copy to the other.
You may scratch your head at one or two little things in this, to be honest I don't know why they're there, they just appear to make the output correct with certain inputs. Just not all inputs, it would seem.
So, without further ado:-
Code:void bitcpy(unsigned char *lpDest, int iDestBit, unsigned char *lpSrc, int iSrcBit, int iLength) { int iCopied = 0, iDestShift, iSrcShift; unsigned char ucDestEndMask, ucDestStartMask, ucSrcEndMask; // Please don't feed me rubbish if (!lpDest || !lpSrc) return; // Set up shifts and masks for initial copy iDestShift = iDestBit & 7; iSrcShift = iSrcBit & 7; ucDestEndMask = 0xFF >> ((iDestBit + iLength) & 7); ucDestStartMask = ~(0xFF >> iDestShift); if (!((iDestBit + iLength) & 7)) ucDestEndMask = ~ucDestEndMask; while (iCopied < iLength) { // Recalculate mask if first dest byte needed more than one copy if (iCopied > 0 && (iDestBit + iCopied) <= 8) { if (iDestShift) ucDestStartMask = ~(0xFF >> iDestShift); else ucDestStartMask = ~(0xFF << iSrcShift); } // Final dest byte? if ((iDestBit + iCopied) >= (iLength & ~7)) { // Modify mask and keep trailing bits safe if (iDestShift) ucDestStartMask = 0xFF >> iDestShift; else ucDestStartMask = 0xFF << iSrcShift; ucDestEndMask |= ucDestStartMask; *lpDest &= ucDestEndMask; if (!(iCopied & 7) && iDestShift) *lpDest |= ((*lpSrc & ucSrcEndMask) >> iSrcShift) << iDestShift; else *lpDest |= ((*lpSrc & ucSrcEndMask) << iSrcShift) >> iDestShift; } else { *lpDest &= ucDestStartMask; if (iCopied && !(iCopied & 7) && iDestShift) *lpDest |= (*lpSrc >> iSrcShift) << iDestShift; else *lpDest |= ((*lpSrc << iSrcShift) & 0xFF) >> iDestShift; } // How many bits did we copy? if (iDestShift) iCopied += 8 - iDestShift; else iCopied += 8 - iSrcShift; // Clamp for calculations if (iCopied > iLength) iCopied = iLength; // Recalculate shifts iDestShift = (iDestBit + iCopied) & 7; iSrcShift = (iSrcBit + iCopied) & 7; // Flip mask if (ucDestStartMask) ucDestStartMask = ~ucDestStartMask; if (!iDestShift) lpDest++; if (!iSrcShift) lpSrc++; } }