Jua*_*uan 0 c bit-manipulation
我想反转二进制文件
unsigned short gf_t = 44 // = 00101100
Run Code Online (Sandbox Code Playgroud)
在C语言的00110100.我将如何使用按位运算符?
pdta:我的电脑有32位模式.
如有疑问,请参阅Bit Twiddling Hacks页面.事实上,在那里你可以找到一个非常简单的算法来做你想要的......
反转位明显的方式
Run Code Online (Sandbox Code Playgroud)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 zero2004年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位数量:
Run Code Online (Sandbox Code Playgroud)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_BIT是16,则适当的用法仅需要前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);
Run Code Online (Sandbox Code Playgroud)
话虽如此,为什么不使用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));
}
Run Code Online (Sandbox Code Playgroud)
你可以这样做(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);
Run Code Online (Sandbox Code Playgroud)
你可以在这里找到更多这样的技巧.以下是使用此代码段的ideone链接.
如果您想了解这一点,请编写示例中使用的"幻数"的二进制表示:
0x5555 是 01010101010101010x3333 是 00110011001100110x0F0F 是 00001111000011110x00FF 是 0000000011111111该&操作清除了"不需要的"位; 移位将所需部分重新定位在由掩蔽操作打开的"零间隙"上,最后|重新组合这两部分.