假设我有一个包含六个未知值的字节:
???1?0??
我想交换第2位和第4位(不用更改任何?
值):
???0?1??
但是我如何在C中的一次操作中执行此操作?
我在微控制器上每秒执行此操作数千次,因此性能是首要任务。
“切换”这些位会很好。即使这与交换位不同,切换也可以用于我的目的。
答案 0 :(得分:30)
尝试:
x ^= 0x14;
切换两个位。当你第一次提到交换然后给出一个切换示例时,这有点不清楚。无论如何,交换位:
x = precomputed_lookup [x];
其中precomputed_lookup是一个256字节的数组,可能是最快的方式,它取决于相对于处理器速度的内存速度。否则,它是:
x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2);
编辑:有关切换位的更多信息。
当xor(^
)两个整数值在一起时,xor在位级执行,如下所示:
for each (bit in value 1 and value 2)
result bit = value 1 bit xor value 2 bit
使第一个值的第0位与第二个值的第0位进行异或,第1位与第1位进行异或,依此类推。 xor操作不会影响值中的其他位。实际上,它是许多位上的并行位xor。
查看xor的真值表,你会看到xor'ing有点值'1'有效地切换了这个位。
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
因此,要切换位1和3,请写一个二进制数,其中一个位于您希望该位切换的位置,而一个零位,您希望保持该值不变:
00001010
转换为十六进制:0x0a。您可以根据需要切换多个位:
0x39 = 00111001
将切换位0,3,4和5
答案 1 :(得分:11)
你不能使用bit-fiddling在一条指令中“交换”两位(即位改变位置,而不是值)。
如果你想真正交换它们的最佳方法可能是查找表。这适用于许多“尴尬”的转变。
BYTE lookup[256] = {/* left this to your imagination */};
for (/*all my data values */)
newValue = lookup[oldValue];
答案 2 :(得分:5)
以下方法不是单个C指令,它只是另一个小巧的方法。该方法简化为 Swapping individual bits with XOR 。
如Roddy's answer中所述,查找表最好。我只是建议你,以防你不想使用它。这也确实会交换位,而不仅仅是切换(也就是说,位2中的任何内容都将在4中,反之亦然)。
r:结果
x =((b>&gt; 2)^(b&gt;&gt; 4))&amp; 0×01
r = b ^((x <&lt; 2)|(x <&lt; 4))
快速解释:获取您想要查看的两个位并对它们进行异或,将值存储到x
。通过将此值移回第2位和第4位(和OR'ing在一起),您将得到一个掩码,当与b
进行异或时,将交换您的两个原始位。下表显示了所有可能的情况。
bit2: 0 1 0 1
bit4: 0 0 1 1
x : 0 1 1 0 <-- Low bit of x only in this case
r2 : 0 0 1 1
r4 : 0 1 0 1
我没有对此进行全面测试,但对于少数情况我很快就尝试了它似乎有效。
答案 3 :(得分:4)
这可能没有优化,但应该有效:
unsigned char bit_swap(unsigned char n, unsigned char pos1, unsigned char pos2)
{
unsigned char mask1 = 0x01 << pos1;
unsigned char mask2 = 0x01 << pos2;
if ( !((n & mask1) != (n & mask2)) )
n ^= (mask1 | mask2);
return n;
}
答案 4 :(得分:2)
下面的函数将交换第2位和第4位。如有必要,您可以使用它来预先计算查找表(以便交换成为单个操作):
unsigned char swap24(unsigned char bytein) {
unsigned char mask2 = ( bytein & 0x04 ) << 2;
unsigned char mask4 = ( bytein & 0x10 ) >> 2;
unsigned char mask = mask2 | mask4 ;
return ( bytein & 0xeb ) | mask;
}
我在一个单独的行上写了每个操作,以使其更清晰。
答案 5 :(得分:0)
假设你的值是x,即x = ??? 1?0 ??
这个操作可以切换这两个位:
x = x ^ ((1<<2) | (1<<4));
答案 6 :(得分:0)
#include<stdio.h>
void printb(char x) {
int i;
for(i =7;i>=0;i--)
printf("%d",(1 & (x >> i)));
printf("\n");
}
int swapb(char c, int p, int q) {
if( !((c & (1 << p)) >> p) ^ ((c & (1 << q)) >> q) )
printf("bits are not same will not be swaped\n");
else {
c = c ^ (1 << p);
c = c ^ (1 << q);
}
return c;
}
int main()
{
char c = 10;
printb(c);
c = swapb(c, 3, 1);
printb(c);
return 0;
}
答案 7 :(得分:0)
void swap_bits(uint32_t& n, int a, int b) {
bool r = (n & (1 << a)) != 0;
bool s = (n & (1 << b)) != 0;
if(r != s) {
if(r) {
n |= (1 << b);
n &= ~(1 << a);
}
else {
n &= ~(1 << b);
n |= (1 << a);
}
}
}
n
是要交换的整数,a
和b
是要交换的位的位置(索引),从较低位开始计数并从零开始。
使用您的示例(n = ???1?0??
),您可以按如下方式调用该函数:
swap_bits(n, 2, 4);
基本原理:如果它们不同,您只需交换这些位(这就是为什么r != s
)。在这种情况下,其中一个是1而另一个是0.之后,只需要注意您要完成一个位设置操作和一个位清除操作。< / p>