我有点不知所措,我想从一个字符串(来自网络)中提取多达64位的定义的bitoffset和bitlength(unsigned long long)。
字符串可以是未定义的长度,所以我需要确保只能访问它Bytewise。 (也意味着我不能使用_bextr_u32内在的)。我不能使用std bitset类,因为它不允许使用偏移量提取多个位,并且只允许提取预定义的位数。
所以我已经计算了byteoffset(在字符串中)和bitoffset(在起始字节内)。
m_nByteOffset = nBitOffset / 8;
m_nBitOffset = nBitOffset % 8;
现在我可以得到起始地址
const char* sSource = str.c_str()+m_nByteOffset;
和位掩码
unsigned long long nMask = 0xFFFFFFFFFFFFFFFFULL >> (64-nBitLen);
但是现在我无法弄清楚如何从中提取多达64位,因为没有128位整数可用。
unsigned long long nResult = ((*(unsigned long long*)sSource) >> m_nBitOffset) & nMask;
这仅适用于高达64位的偏移位,如何将其扩展为独立于bitoffset的64位。而且,由于这不是按字节顺序访问,因此可能会导致内存读取访问冲突。
所以我真的在寻找这个问题的字节解决方案,最多可以解决64位问题。 (最好是C或内在函数)
更新:经过大量搜索和测试后,我可能会使用RakNet的这个功能: https://github.com/OculusVR/RakNet/blob/master/Source/BitStream.cpp#L551
答案 0 :(得分:2)
要按字节顺序执行,只需读取字符串(BTW最好将其解释为uint8_t
而不是char
的序列),一次一个字节,通过移位更新结果它留下了8和or
当前字节。唯一的复杂因素是第一位和最后一位,它们都要求您读取一部分字节。对于第一部分,只需使用位掩码来获得所需的位,并在最后一部分向下移动所需的量。这是代码:
const uint8_t* sSource = reinterpret_cast<const uint8_t*>(str.c_str()+m_nByteOffset);
uint64_t result = 0;
uint8_t FULL_MASK = 0xFF;
if(m_nBitOffset) {
result = (*sSource & (FULL_MASK >> m_nBitOffset));
nBitLen -= (8 - m_nBitOffset);
sSource++;
}
while(nBitLen > 8) {
result <<= 8;
result |= *sSource;
nBitLen -= 8;
++sSource;
}
if(nBitLen) {
result <<= nBitLen;
result |= (*sSource >> (8 - nBitLen));
}
return result;
答案 1 :(得分:1)
这就是我在现代C ++风格中的表现。
位长度由缓冲区extractedBits
的大小决定:您可以使用具有所需大小的任何其他数据类型(甚至数组类型),而不是使用unsigned long long
。
unsigned long long extractedBits;
char* extractedString = reinterpret_cast<char*>(&extractedBits);
std::transform(str.begin() + m_nByteOffset,
str.begin() + m_nByteOffset + sizeof(extractedBits),
str.begin() + m_nByteOffset + 1,
extractedString,
[=](char c, char d)
{
char bitsFromC = (c << m_nBitOffset);
char bitsFromD =
(static_cast<unsigned char>(d) >> (CHAR_BIT - m_nBitOffset));
return bitsFromC | bitsFromD;
});