将最低有效位从4字节数组重新分配到半字节

时间:2012-01-10 11:56:22

标签: c bit-manipulation bit-packing

我希望将32位值的0,8,16,24位分别移动到位0,1,2,3。输入和输出中的所有其他位都将为零。

显然我可以这样做:

c = c>>21 + c>>14 + c>>7 + c;
c &= 0xF;

但是有更快(更少指令)的方式吗?

3 个答案:

答案 0 :(得分:2)

c = (((c&BITS_0_8_16_24) * BITS_0_7_14_21) >> 21) & 0xF;

或者等待Intel Haswell处理器,只需一条指令(pext)即可完成所有这些操作。

<强>更新

考虑到clarified constraints并假设32-bit unsigned values,代码可能会简化为:

c = (c * BITS_7_14_21_28) >> 28;

答案 1 :(得分:1)

如果您不关心可移植性,并且可以使用SSE指令,请查看PMOVMSKB指令及其编译器内在函数。 [我注意到你的位位置是包含32位字的4个字节中最重要的(符号)位。]

答案 2 :(得分:0)

不是编写一些混淆的单行goo,而是下面的代码是我要写的,以获得最大的可移植性和可维护性。我会让优化器担心它是否是最有效的代码。

#include <stdint.h>
#include <limits.h>
#include <stdio.h>

#define BITS_TO_MOVE  4

static const uint32_t OLD_MASK [BITS_TO_MOVE] =
{
  0x0008u,
  0x0080u,
  0x0800u,
  0x8000u
};

static const uint32_t NEW_MASK [BITS_TO_MOVE] =
{
  0x1000u,
  0x2000u,
  0x4000u,
  0x8000u
};


int main()
{
  uint32_t  c     = 0xAAAAu;
  uint32_t  new_c = 0;
  uint8_t   i;

  printf("%.4X\n", c);


  for(i=0; i<BITS_TO_MOVE; i++)
  {
    if ( (c & OLD_MASK[i]) > 0 )
    {
      new_c |= NEW_MASK[i];
    }
  }


  printf("%.4X\n", new_c);
  getchar();

  return 0;
}