使用按位运算符反转无符号短向量

时间:2012-09-10 19:03:17

标签: c bit-manipulation

我想反转二进制文件

unsigned short gf_t  = 44 // = 00101100

在C语言的00110100中。我将如何使用按位运算符?

pdta:我的电脑有32位模式。

4 个答案:

答案 0 :(得分:6)

如有疑问,请参阅Bit Twiddling Hacks page。事实上,在那里你可以找到一个非常简单的算法来做你想要的......

  

以明显的方式反转位

unsigned int v;     // input bits to be reversed
unsigned int r = v; // r will be reversed bits of v; first get LSB of v
int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end

for (v >>= 1; v; v >>= 1)
{   
  r <<= 1;
  r |= v & 1;
  s--;
}
r <<= s; // shift when v's highest bits are zero 
     

2004年10月15日,Michael Hoisie指出了原版中的一个错误。 Randal E. Bryant建议在2005年5月3日删除一项额外的操作.Behdad Esfabod提出了一个微小的改变,消除了2005年5月18日循环的一次迭代。然后,在2007年2月6日,Liyong Zhou提出了一个更好的循环版本虽然v不是0,所以不是迭代所有位而是提前停止。

然而,还有一些很好的方法。您可以查看这些并尝试理解它们以便学习:-)例如,这是一个特别有趣的形式......

  

在5 * lg(N)操作中并行反转N位数量:

unsigned int v; // 32-bit word to reverse bit order

// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ... 
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = ( v >> 16             ) | ( v               << 16);

请注意,如果sizeof(unsigned short) * CHAR_BIT16,则相应的用法仅需要前4个转置 - 请参阅以下内容:

unsigned short v;

// swap odd and even bits
v = ((v >> 1) & 0x5555) | ((v & 0x5555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x3333) | ((v & 0x3333) << 2);
// swap nibbles ... 
v = ((v >> 4) & 0x0F0F) | ((v & 0x0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF) | ((v & 0x00FF) << 8);

话虽如此,为什么不使用uint16_t(如果有的话)?

以下是工作示例(请参阅ideone):

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

inline uint16_t reverse(uint16_t v) {
  v = ((v >> 1) & 0x5555) | ((v & 0x5555) << 1); /* swap odd/even bits */
  v = ((v >> 2) & 0x3333) | ((v & 0x3333) << 2); /* swap bit pairs */
  v = ((v >> 4) & 0x0F0F) | ((v & 0x0F0F) << 4); /* swap nibbles */
  v = ((v >> 8) & 0x00FF) | ((v & 0x00FF) << 8); /* swap bytes */
  return v;
}

main() {
  uint16_t gf_t = 44;
  printf("%hu\n", reverse(gf_t));
}

答案 1 :(得分:5)

您可以这样做(v是一个16位数字):

v = ((v >> 1) & 0x5555) | ((v & 0x5555) << 1);
v = ((v >> 2) & 0x3333) | ((v & 0x3333) << 2);
v = ((v >> 4) & 0x0F0F) | ((v & 0x0F0F) << 4);
v = ((v >> 8) & 0x00FF) | ((v & 0x00FF) << 8);
  • 第一行交换奇数和偶数位
  • 第二行交换连续对
  • 第三行交换四位组
  • 最后一行交换两个字节

你可以找到更多这样的技巧here。这是link to ideone with this code snippet

如果您想了解这一点,请编写示例中使用的“幻数”的二进制表示:

  • 0x55550101010101010101
  • 0x33330011001100110011
  • 0x0F0F0000111100001111
  • 0x00FF0000000011111111

&操作清除“不需要的”位;移位将所需部分重新定位在由掩蔽操作打开的“零间隙”上,最后|重新组合这两部分。

答案 2 :(得分:1)

通常你用and输入1得到它的LSB。 Or进入结果。将结果向左移动一点,输入右移一点。重复总共32次迭代。

答案 3 :(得分:0)

二进制文件是0000000000101100 - 简而言之有16位。

//包括去这里

int main() {

unsigned short gf_t = 44;     cout&lt;&lt; hex&lt;&lt; gf_t&lt;&lt; ENDL;

unsigned short gf_r = 0;
for ( int iter = 0; iter < sizeof(short) * 8; ++iter )
{
unsigned short tmp = gf_t;
tmp = tmp & 1;
gf_r = (gf_r << 1 ) | tmp;
gf_t = gf_t >> 1;
}

cout << hex << gf_r << endl;

}