C++ 从缓冲区中删除第n位,并移动其余的
给定长度为C++ 从缓冲区中删除第n位,并移动其余的,c++,c,bit-manipulation,C++,C,Bit Manipulation,给定长度为x的uint8\t缓冲区,我试图想出一个函数或宏,可以删除第n位(或n到n+I),然后左移剩余的位 示例#1: 对于输入0b76543210 0b76543210…,则输出应为0b76543217 0b654321… 示例2:如果输入为: uint8_t input[8] = { 0b00110011, 0b00110011, ... }; 不带第一位的输出应为 uint8_t output[8] = { 0b00110010, 0b01100
x
的uint8\t
缓冲区,我试图想出一个函数或宏,可以删除第n位(或n到n+I),然后左移剩余的位
示例#1:
对于输入0b76543210 0b76543210…
,则输出应为0b76543217 0b654321…
示例2:如果输入为:
uint8_t input[8] = {
0b00110011,
0b00110011,
...
};
不带第一位的输出应为
uint8_t output[8] = {
0b00110010,
0b01100100,
...
};
我尝试了以下方法来删除第一个位,但对第二组位无效
/* A macro to extract (a-b) range of bits without shifting */
#define BIT_RANGE(N,x,y) ((N) & ((0xff >> (7 - (y) + (x))) << ((x))))
void removeBit0(uint8_t *n) {
for (int i=0; i < 7; i++) {
n[i] = (BIT_RANGE(n[i], i + 1, 7)) << (i + 1) |
(BIT_RANGE(n[i + 1], 1, i + 1)) << (7 - i); /* This does not extract the next element bits */
}
n[7] = 0;
}
/*在不移位的情况下提取(A-b)位范围的宏*/
#定义位范围(N,x,y)((N)和((0xff>>(7-(y)+(x)))类似于此的东西应该可以工作:
template<typename S> void removeBit(S* buffer, size_t length, size_t index)
{
const size_t BITS_PER_UNIT = sizeof(S)*8;
// first we find which data unit contains the desired bit
const size_t unit = index / BITS_PER_UNIT;
// and which index has the bit inside the specified unit, starting counting from most significant bit
const size_t relativeIndex = (BITS_PER_UNIT - 1) - index % BITS_PER_UNIT;
// then we unset that bit
buffer[unit] &= ~(1 << relativeIndex);
// now we have to shift what's on the right by 1 position
// we create a mask such that if 0b00100000 is the bit removed we use 0b00011111 as mask to shift the rest
const S partialShiftMask = (1 << relativeIndex) - 1;
// now we keep all bits left to the removed one and we shift left all the others
buffer[unit] = (buffer[unit] & ~partialShiftMask) | ((buffer[unit] & partialShiftMask) << 1);
for (int i = unit+1; i < length; ++i)
{
//we set rightmost bit of previous unit according to last bit of current unit
buffer[i-1] |= buffer[i] >> (BITS_PER_UNIT-1);
// then we shift current unit by one
buffer[i] <<= 1;
}
}
模板void removeBit(S*缓冲区、大小长度、大小索引)
{
常数大小每单位比特数=sizeof(S)*8;
//首先,我们找到包含所需位的数据单元
常量大小单位=每单位的索引/位;
//哪个索引的位在指定的单位内,从最高有效位开始计数
const size_t relativeIndex=(每单位比特数-1)-索引%BITS_每单位;
//然后,我们取消了这一点
buffer[unit]&=~(1这实际上是两个子问题:从每个字节中删除位并打包结果。这是下面的代码流程。我不会为此使用宏。进行了太多操作。如果您担心该级别的性能,只需内联函数即可
#include <stdio.h>
#include <stdint.h>
// Remove bits n to n+k-1 from x.
unsigned scrunch_1(unsigned x, int n, int k) {
unsigned hi_bits = ~0u << n;
return (x & ~hi_bits) | ((x >> k) & hi_bits);
}
// Remove bits n to n+k-1 from each byte in the buffer,
// then pack left. Return number of packed bytes.
size_t scrunch(uint8_t *buf, size_t size, int n, int k) {
size_t i_src = 0, i_dst = 0;
unsigned src_bits = 0; // Scrunched source bit buffer.
int n_src_bits = 0; // Initially it's empty.
for (;;) {
// Get scrunched bits until the buffer has at least 8.
while (n_src_bits < 8) {
if (i_src >= size) { // Done when source bytes exhausted.
// If there are left-over bits, add one more byte to output.
if (n_src_bits > 0) buf[i_dst++] = src_bits << (8 - n_src_bits);
return i_dst;
}
// Pack 'em in.
src_bits = (src_bits << (8 - k)) | scrunch_1(buf[i_src++], n, k);
n_src_bits += 8 - k;
}
// Write the highest 8 bits of the buffer to the destination byte.
n_src_bits -= 8;
buf[i_dst++] = src_bits >> n_src_bits;
}
}
int main(void) {
uint8_t x[] = { 0xaa, 0xaa, 0xaa, 0xaa };
size_t n = scrunch(x, 4, 2, 3);
for (size_t i = 0; i < n; i++) {
printf("%x ", x[i]);
}
printf("\n");
return 0;
}
这写的是D65A b
。其他一些测试用例也可以使用。在x86上,有一条说明(等等,什么?):pdep/pext
,由BMI2
指令集扩展添加。谢谢,这很有趣,我正在尝试一下。我对这个问题感到有点困惑。图表表明,您不只是想删除一位,实际上还想从由x八位字节数组表示的位流中删除位s+8*I,其中s在[0,7],也就是说,这是位流压缩的一种特殊形式。一种简单的方法是简单地循环输入位,保持源和目标位的独立运行计数,以指示何时抑制位复制以及何时检索/存放下一个八位字节。对于您的目的来说,这会太慢吗?如果假设不会o作为“跨平台”,为什么要使用“汇编”和“内联汇编”标记?此外,您还没有回答njuffa关于您的图表如何与您的问题相矛盾的问题。问题的第一行表示您要删除一位(或一系列连续位)从缓冲区中删除。图表显示多个非连续位被删除。您必须决定您的问题是要求跨平台解决方案还是平台特定解决方案。在前一种情况下,您不适合发布平台特定的答案,在后一种情况下,您需要命名平台。谢谢,这实际上是可行的,我想指出endian的问题,但是你已经提到了,所以,谢谢你。非常感谢你,我喜欢你花时间提供模板函数的方式,但不幸的是,这并没有产生所需的输出,我正试图修改代码一点,以便使用uint8\t缓冲区。
#include <stdio.h>
#include <stdint.h>
// Remove bits n to n+k-1 from x.
unsigned scrunch_1(unsigned x, int n, int k) {
unsigned hi_bits = 0xffu << n;
return (x & ~hi_bits) | ((x >> k) & hi_bits);
}
// Remove bits n to n+k-1 from each byte in the buffer,
// then pack right. Return number of packed bytes.
size_t scrunch(uint8_t *buf, size_t size, int n, int k) {
size_t i_src = 0, i_dst = 0;
unsigned src_bits = 0; // Scrunched source bit buffer.
int n_src_bits = 0; // Initially it's empty.
for (;;) {
// Get scrunched bits until the buffer has at least 8.
while (n_src_bits < 8) {
if (i_src >= size) { // Done when source bytes exhausted.
// If there are left-over bits, add one more byte to output.
if (n_src_bits > 0) buf[i_dst++] = src_bits;
return i_dst;
}
// Pack 'em in.
src_bits |= scrunch_1(buf[i_src++], n, k) << n_src_bits;
n_src_bits += 8 - k;
}
// Write the lower 8 bits of the buffer to the destination byte.
buf[i_dst++] = src_bits;
src_bits >>= 8;
n_src_bits -= 8;
}
}
int main(void) {
uint8_t x[] = { 0xaa, 0xaa, 0xaa, 0xaa };
size_t n = scrunch(x, 4, 2, 3);
for (size_t i = 0; i < n; i++) {
printf("%x ", x[i]);
}
printf("\n");
return 0;
}