简体   繁体   English

从std :: string逐字节提取具有位偏移的连续位

[英]Extracting continuos bits from a std::string bytewise with a bit offset

I'm kind of at a loss i want to extract up to 64bits with a defined bitoffset and bitlength (unsigned long long) from a string (coming from network). 我有点不知所措,我想从一个字符串(来自网络)中提取一个具有定义的位偏移和位长(无符号长长)的64位。

The string can be at an undefined length, so i need to be sure to only access it Bytewise. 该字符串可以是未定义的长度,因此我需要确保仅按字节访问它。 (Also means i cant use _bextr_u32 intrinsic). (也意味着我不能使用_bextr_u32内在函数)。 I cant use the std bitset class because it doesnt allow extraction of more then one bit with an offset and also only allows extraction of a predefined number of bits. 我不能使用std位集类,因为它不允许提取具有偏移量的多个位,而且还仅允许提取预定义数量的位。

So I already calculate the byteoffset (within the string) and bitoffset (within the starting byte). 因此,我已经计算出byteoffset(在字符串内)和bitoffset(在起始字节内)。

m_nByteOffset = nBitOffset / 8;
m_nBitOffset = nBitOffset % 8;

Now i can get the starting address 现在我可以得到起始地址

const char* sSource = str.c_str()+m_nByteOffset;

And the bitmask 和位掩码

unsigned long long nMask = 0xFFFFFFFFFFFFFFFFULL >> (64-nBitLen);

But now I just cant figure out how to extract up to 64 bits from this as there are no 128 bit integers available. 但是现在我无法弄清楚如何从中提取最多64位,因为没有可用的128位整数。

unsigned long long nResult = ((*(unsigned long long*)sSource) >> m_nBitOffset) & nMask;

This only works for up to 64-bitoffset bits, how can i extend it to really work for 64 bit indepently of the bitoffset. 这仅适用于最多64位偏移量的位,我如何扩展它使其真正独立于bitoffset适用于64位。 And also as this is not a bytewise access it could cause a memory read access violation. 另外,由于这不是按字节访问,因此可能会导致内存读取访问冲突。

So im really looking for a bytewise solution to this problem that works for up to 64 bits. 因此,我真的在寻找针对此问题的按字节解决方案,该解决方案最多可使用64位。 (preferably C or intrinsics) (最好是C或内在函数)

Update: After searching and testing a lot I will probably use this function from RakNet: https://github.com/OculusVR/RakNet/blob/master/Source/BitStream.cpp#L551 更新:经过大量搜索和测试后,我可能会从RakNet使用此功能: https : //github.com/OculusVR/RakNet/blob/master/Source/BitStream.cpp#L551

To do it byte-wise, just read the string (which BTW it is better to interpret as a sequence of uint8_t rather than char ) one byte at a time, updating your result by shifting it left 8 and or ing it with the current byte. 要按字节进行操作,只需一次读取一个字节(该字符串最好将其解释为uint8_t而不是char的序列),一次读取一个字节,将结果向左移8 or与当前字节对应即可更新结果。 The only complications are the first bit and the last bit, which both require you to read a part of a byte. 唯一的复杂性是第一位和最后一位,这两者都需要您读取字节的一部分。 For the first part simply use a bit mask to get the bit you need, and for the last part down shift it by the amount needed. 对于第一部分,只需使用位掩码即可获取所需的位,对于最后一部分,可将其向下移位所需的数量。 Here is the code: 这是代码:

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;

This is how I would do it in modern C++ style. 这就是我将以现代C ++风格进行的方式。 The bit length is determined by the size of the buffer extractedBits : instead of using an unsigned long long , you could also use any other data type (or even array type) with the desired size. 位长度由缓冲区extractedBits的大小确定:除了使用unsigned long long ,还可以使用具有所需大小的任何其他数据类型(甚至数组类型)。

See it live 现场观看

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;
               });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM