繁体   English   中英

C ++中的运行时位复制(位掩码)

[英]Run-time bit copy (bit-masking) in C++

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

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

char8_t data[8];
int32_t out;
int32_t offset;
int32_t length;

offset=24; length=4; 图形 offset=24; length=4; offset=24; length=4;

偏移量和长度都仅在运行时可用。 因此,我想避免创建位掩码。 我亲自解决了此问题,方法是将整个数组转换为int64_t,然后右移(64-offset-length),然后左移(64-length)。

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

问题是:如果我的阵列更长,将没有原始数据来捕获整个阵列。 我的解决方案不再起作用。 有更好的(缩放)方法吗?

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

我考虑过的替代方法是:通过遍历数组并向左移动,在“ out”上加+ =。 毫不客气!

我知道那里也有类似的问题,但是要么答案很差,要么对性能的影响很大。

首先,您的方法将取决于字节序,即系统是在各个8字节存储块的开头还是结尾存储最高有效字节。

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

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

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

从而,您的“解码器”将被拉紧到原始数据的顺序/含义; 您的data可能会比最大的整数数据类型更长; 并且避免了因将带符号的整数值移到带符号的位上而导致的未定义行为。

如果偏移量不是8的倍数,即“值”不是从字节的开头开始,则仍然可以使用移位操作来纠正此错误。 假设该值以2位的偏移量开始; 然后,您可以编写:

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

但是-最终-您的目标将被限制为特定的位数,因为您特定平台上的C语言将为每种原始数据类型保证特定的大小, unsigned long long可能仍为64位。 此限制是由实现定义的,标准保证每种数据类型的位数最少。 这个限制是来自寄存器还是其他,您不知道-它的实现已定义。

您是否尝试过std::vector<bool> 它是std::vectorstd::vector ,它结合了std::vector的动态大小和std::bitset紧凑性。

我将使用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();

我使用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<>高效地保存任意位长度的值。

暂无
暂无

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

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