WINCE6中SDBus驱动中有如下代码,用来从一段给定的内存中的指定位置取出指定的几位数据。
就这样一个功能,使用了如此多的代码,我个人认为是由于使用了错误的数据类型从而使其变得很复杂
// Shifts pbInput down by dwBitOffset.
static
VOID
ShiftBytes(PBYTE pbInput, ULONG cbInput, DWORD dwBitOffset, PBYTE pbOutput)
{
PREFAST_DEBUGCHK(pbInput);
PREFAST_DEBUGCHK(pbOutput);
DWORD dwByteIndex = dwBitOffset / 8;
dwBitOffset %= 8;
DWORD dwRemainderShift = 8 - dwBitOffset;
// Only copy 4 bytes max.
DWORD dwEndIndex = min(dwByteIndex + sizeof(DWORD), cbInput);
DWORD dwCurrOutputIndex = 0;
while (dwByteIndex < dwEndIndex) {
DEBUGCHK(dwCurrOutputIndex < sizeof(DWORD));
DEBUGCHK(dwByteIndex < cbInput);
pbOutput[dwCurrOutputIndex] = pbInput[dwByteIndex] >> dwBitOffset;
++dwByteIndex;
if (dwByteIndex != cbInput) {
BYTE bTemp = pbInput[dwByteIndex];
bTemp <<= dwRemainderShift;
pbOutput[dwCurrOutputIndex] |= bTemp;
}
++dwCurrOutputIndex;
}
}
///////////////////////////////////////////////////////////////////////////////
// GetBitSlice - Get a bit slice from a stream of bytes
// Input: pBuffer - buffer containing data stream
// cbBuffer - size of buffer in bytes
// dwBitOffset - bit offset from start of buffer
// ucBitCount - number of bits (less than or equal to 32)
// Output:
//
// Return: returns a DWORD contain the bit slice shifted to fill the least significant bits
// Notes: will raise an SEH exception if integer overflow occurs
///////////////////////////////////////////////////////////////////////////////
DWORD CSDDevice::GetBitSlice(PUCHAR pBuffer, ULONG cbBuffer, DWORD dwBitOffset, UCHAR ucBitCount)
{
UCHAR rgbShifted[4] = { 0 };
if (ucBitCount > 32) {
DEBUG_CHECK(FALSE, (TEXT("GetBitSlice: invalid number of bits \n")));
return 0;
}
typedef SafeInt<DWORD> SafeDW;
// Exception will be raised on the next line if there is an overflow.
if ( (SafeDW(dwBitOffset) + SafeDW(ucBitCount)) > (SafeDW(cbBuffer) * 8) ) {
DEBUG_CHECK(FALSE, (TEXT("GetBitSlice: invalid bit offset given the number of bits \n")));
return 0;
}
// Shift the pBuffer down by dwBitOffset bits.
ShiftBytes(pBuffer, cbBuffer, dwBitOffset, rgbShifted);
DWORD dwUsedBytes; // How many bytes have valid data.
if (ucBitCount % 8 == 0) {
// Return a byte multiple.
dwUsedBytes = ucBitCount / 8;
}
else {
// Clear the last used byte of upper bits.
DWORD dwLastByteIndex = (ucBitCount - 1) / 8;
DWORD dwRemainderShift = 8 - (ucBitCount % 8);
rgbShifted[dwLastByteIndex] <<= dwRemainderShift;
rgbShifted[dwLastByteIndex] >>= dwRemainderShift;
dwUsedBytes = dwLastByteIndex + 1;
}
// Clear the unused bytes.
if (dwUsedBytes != sizeof(rgbShifted)) {
memset(rgbShifted + dwUsedBytes, 0, sizeof(rgbShifted) - dwUsedBytes);
}
DWORD dwRet;
memcpy(&dwRet, rgbShifted, sizeof(dwRet));
return dwRet;
}
以下是我自己为了实现相同功能而写的代码
- WORD GetBitValue( PBYTE pBuf, DWORD dwBit, DWORD dwNum )
- {
- DWORD dwByte=dwBit/8;
- DWORD dwBitinByte=dwBit & 0x7;
- if(dwBitinByte + dwNum >24 )
- return 0; //Not supported.
- else if(dwBitinByte + dwNum >16 )
- return (pBuf[dwByte]>>(dwBitinByte) ) |
- (pBuf[dwByte+1]<<( 8- dwBitinByte) ) |
- ( pBuf[dwByte+2] << (16-dwBitinByte) );
- else if(dwBitinByte + dwNum >8 )
- return (pBuf[dwByte]>>(dwBitinByte) ) | (pBuf[dwByte+1]<<( 8- dwBitinByte) ) ;
- else
- return pBuf[dwByte]>>(dwBitinByte);
- }
当然我的代码有点缺陷:取出的数据高位没有清零,要做到这点是很容易的。