在uint8_t块的特定索引处添加位

所以我有一个指向uint8_t数组的指针,形式为:

uint8_t* array; #64 bit array

我需要通过向右移动位并在2的幂的索引处插入0或1的位来修改此数组,从而生成72位的数组。

uint8_t newArr[9];

修改数组的最佳方法是什么,这样我就可以在计算出的特定位置添加位。我想到了将数组转换为char数组,然后逐位添加位的想法。但是,有没有比这更快,更容易的方法。

因此,如果我有一个指向uint8_t形式的位数组的指针,例如:

000100001 11001111 01101101 11000001 11100000 00101111 11111001 10010010

我需要将其修改为uint8_t [9]数组,以便插入在新数组的0、1、2、4、8、16、32、64处指定的位,如下所示:是错误的)

00000000 11001111 11001111 11001111 11001111 01101101 01101101 10010010 00100001

但是我不知道如何在不移动所有位的情况下向右移动特定位。例如,如果我将从索引2 1开始的所有位向右移,然后将从索引4开始的所有位向右移一。

wzq185833229 回答:在uint8_t块的特定索引处添加位

假设您从以下内容开始:

block-1576017486920

您要插入以下位置(八进制): 0、1、2、4、10、20、40、100

这意味着您需要以下内容:

src[0]   src[1]   src[2]   src[3]   src[4]   src[5]   src[6]   src[7]
-------- -------- -------- -------- -------- -------- -------- --------
       7        6        5        4        3        2        1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh

所以

dst[0]   dst[1]   dst[2]   dst[3]   dst[4]   dst[5]   dst[6]   dst[7]   dst[8]
-------- -------- -------- -------- -------- -------- -------- -------- --------
       1
       0        7        6        5        4        3        2        1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000

(省略了无用的蒙版。)

,

您可以将输入数组视为64位整数,以使其更快。假设输入和输出值是这样的

array  = aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
newArr = aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000

然后您可以通过这种方式获得所需的结果

uin64_t src = htobe64(*(uint64_t*)array); // operate on big endian
uint64_t* dst = (uint64_t*)newArr;

*dst  = (src & 0xFE00'0000'0000'0000) >> 0; // aaaaaaa
*dst |= (src & 0x01FF'FFFF'FC00'0000) >> 1; // abbbbbbbbccccccccddddddddeeeeee
*dst |= (src & 0x0000'0000'03FF'F800) >> 2; // eeffffffffggggg
*dst |= (src & 0x0000'0000'0000'07F0) >> 3; // ggghhhh
*dst  = be64toh(*dst); // convert back to the native endian
newArr[8] = ((array[7] & 0x0E) << 4) | ((array[7] & 0x01) << 3); // hhh0h000

为避免严格的别名,您可以更改为memcpy,以从array复制到src并从dst复制到newArr

当然,您可能需要对齐输入和输出阵列以提高性能。在许多现代建筑中,这也是必须的

#ifdef _MSC_VER
__declspec(align(8)) uint8_t array[8]; #64 bit array
__declspec(align(8)) uint8_t newArr[9];
#else
uint8_t array[8] __attribute__((aligned(8))); #64 bit array
uint8_t newArr[9] __attribute__((aligned(8)));
#endif

在带有BMI2的现代x86上,您可以使用新的bit deposit instruction直接获取前8个字节

uint64_t src;
memcpy(&src,&array,sizeof src); // avoid strict aliasing
uin64_t src = htobe64(src);

uint64_t dst = _pdep_u64(src >> 4,// aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0
    0b11111110'11111111'11111111'11111111'11111110'11111111'11111110'11111110);
                          // hhh0h000
newArr[8] = _pdep_u32(src,0b11101000);

*dst  = be64toh(*dst); // convert back to the native endian
memcpy(&newArr,&dst,sizeof dst); // avoid strict aliasing
本文链接:https://www.f2er.com/2945921.html

大家都在问