我有一个无符号 32 位整数值,其中包含多组位。一组内的所有位始终相同。 每组的大小相同
n
(从 2 到 32)。组与组之间没有间隙。
我需要将这些位的每一组转换为一位。接下来,我需要如下所示打包这些位:
我提出了以下 C 函数,它迭代这些位并将它们打包为 2 到 32 之间的任意
n
。
uint32_t PackBits(uint32_t value, uint8_t n)
{
uint32_t res = 0;
uint32_t mask = 1; // Also works for: mask= 1 << n-1; mask= 1 << n-2; mask= 1 << n-3; ... ; mask= 1 << n-n;
uint8_t s = 0;
do {
res |= (value & mask) >> s;
mask <<= n;
s += n-1;
} while (mask);
return res;
}
Q:有没有一种方法可以在 C 语言中实现这一目标,而无需循环这些位,并使用一些巧妙的乘法、加法、异或、求反等序列......?
可能它比循环更有效,因为循环不适合管道。
#define MASK(n, x) ((1 << (n + 1)) - 1) << ((x) * (n))
#define BITVAL(val, n , x) ((((val) & MASK(n,x)) == MASK(n,x)) << (x))
#define PACKBITS4(val) (BITVAL(val, 4, 0) + BITVAL(val, 4, 1) + BITVAL(val, 4, 2) + BITVAL(val, 4, 3))
#define PACKBITS5(val) (BITVAL(val, 5, 0) + BITVAL(val, 5, 1) + BITVAL(val, 5, 2))
它适用于 16 位整数,但您可以对所有可能的
n
进行硬编码。当 n
是常量表达式时,它将生成不跳转的代码,如果不是,它将跳转但不循环
https://godbolt.org/z/nzqYsee3Y
它可能会更快,但必须经过测试。