C ++中的运行时位复制(位屏蔽)

时间:2018-04-10 09:30:47

标签: c++ arrays bitmask

我手边有一个问题并以一种方式解决了,但我不知道我是如何解决它的,因为它在每种情况下都不起作用。解决方案必须是C ++(11)。

我有一个char数组和一个int。给定相对于数据的位偏移和长度(以位为单位)。我想从数组中提取offset到offset + length的位并将它们存储在out中。

char8_t data[8];
int32_t out;
int32_t offset;
int32_t length;
<{> Figure offset=24; length=4;

偏移量和长度都只能在运行时使用。因此,我想避免创建位掩码。我亲自通过将完整数组转换为int64_t然后右移(64-offset-length)和左移(64-length)来解决它。

out = (*(int64_t*)data) >> (64-offset-length) << (64-length);

问题:如果我的数组会更长,则没有基元来捕获整个数组。我的解决方案不再适用。有没有更好的(缩放)方法来做到这一点?

在一个理想的世界中,我可以创建一个带有位偏移的指针,但这是C ++不是一个理想的世界。

替代方案我想到:通过迭代数组和左移,将+ =加到“out”上。 相当不优雅!

我知道存在类似的问题,但要么答案很差,要么答案的性能影响很大。

4 个答案:

答案 0 :(得分:1)

首先,您的方法将取决于字节顺序,即系统是否在相应的8字节内存块的开头或末尾存储最高有效字节。

其次,我使用的是无符号数据类型,例如uchar8_t data[8]uint32_t,以便正确处理位移和(自动)类型促销。

如果您确切知道data[8]中存储了特定信息的位置以及顺序,您可以按如下方式编写:

uint32_t out = data[0] + 256*data[1]; 
...

因此,您的&#34;解码器&#34;将收紧原始数据的顺序/含义;您的data可能会比最大的整数数据类型更长;并且可以避免通过在带符号位上移位有符号整数值而引入的未定义行为。

如果您的偏移量不是8的倍数,即&#34;值&#34;不是从字节的开头开始,你仍然可以使用位移操作来纠正这个问题。让我们假设该值以2位的偏移量开始;然后你可以写:

uint32_t out = (data[0] >> 2) + (data[1] << 6) + (data[2] << (6+8))

但是 - 最后 - 你的目标将被限制在特定的位数,因为你的特定平台的C语言将保证每种原始数据类型的特定大小,unsigned long long可能是64比特还在。此限制是实现定义的,标准保证每种数据类型的最小位。无论这个限制是来自寄存器还是其他东西,你都无法知道 - 它的实现已定义。

答案 1 :(得分:1)

你试过std::vector<bool>吗? 它是std::vector的一种特殊化,它将向量的动态大小与std::bitset的紧凑性结合起来。

答案 2 :(得分:1)

我将bitset用作临时的。第一个复制字节在循环中对齐,然后执行位对齐。

unsigned startbit = offset;
unsigned startbyte = startbit / 8;
unsigned endbit = offset + length - 1;
unsigned endbyte = endbit / 8;

bitset<8*(sizeof(out) + 1)> align(0);
for(unsigned byte = endbyte; byte >= startbyte; --byte) { // byte align copy
// for(unsigned byte = startbyte; byte <= endbyte; ++byte) { // check endianess
    align <<= 8;
    align |= data[byte];
}
align >>= startbit % 8; // bit align
align &= ((1 << length) - 1); // mask

out = align.to_ullong();

答案 3 :(得分:0)

我使用std::bitsetboost::dynamic_bitset来表示二进制数据并对其进行操作。如果长度固定,std::bitset效果很好,否则boost::dynamic_bitset是一个不错的选择。这样,您可以使用重载位运算符提取位:

#include <boost/dynamic_bitset.hpp>

using boost::dynamic_bitset;

dynamic_bitset<unsigned char> extract(unsigned char* first, unsigned char* last, int offset, int length) {
   dynamic_bitset<unsigned char> bits(first, last);

   bits >>= bits.size() - (offset  + length);
   bits.resize(length);

   return bits;
}

因此,您可以使用int32_t out;代替dynamic_bitset<>以有效的方式保存任意位长度的值。