在C中通过一次操作交换两位?

时间:2009-06-11 14:56:16

标签: c arduino bit bit-manipulation

假设我有一个包含六个未知值的字节:

???1?0??

我想交换第2位和第4位(不用更改任何?值):

???0?1??

但是我如何在C中的一次操作中执行此操作?

我在微控制器上每秒执行此操作数千次,因此性能是首要任务。

“切换”这些位会很好。即使这与交换位不同,切换也可以用于我的目的。

8 个答案:

答案 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中,反之亦然)。

  • b:你的原始值 - ??? 1?0 ??例如
  • x:只是一个临时
  • 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是要交换的整数,ab是要交换的位的位置(索引),从较低位开始计数并从零开始。

使用您的示例(n = ???1?0??),您可以按如下方式调用该函数:

swap_bits(n, 2, 4);

基本原理:如果它们不同,您只需交换这些位(这就是为什么r != s)。在这种情况下,其中一个是1而另一个是0.之后,只需要注意您要完成一个位设置操作和一个位清除操作。< / p>