簡體   English   中英

在C中通過一次操作交換兩位?

[英]Swap two bits with a single operation in C?

假設我有一個包含六個未知值的字節:

???1?0??

我想交換第2和第4位( 改變任何?值):

???0?1??

但是如何在C中的一次操作中執行此操作

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

可以“切換”這些位。 即使這與交換位不同,切換也可以用於我的目的。

嘗試:

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位xor'ed,第1個第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

您不能使用bit-fiddling在單個指令中“交換”兩個位(即位改變位置,而不是值)。

如果你想真正交換它們的最佳方法可能是查找表。 這適用於許多“尷尬”的轉變。

BYTE lookup[256] = {/* left this to your imagination */};

for (/*all my data values */) 
  newValue = lookup[oldValue];

以下方法不是單個C指令,它只是另一個小巧的方法。 通過使用XOR交換單個位簡化了該方法。

Roddy的回答所述 ,查找表最好。 我只是建議你,以防你不想使用它。 這也確實會交換位,而不僅僅是切換(也就是說,位2中的任何內容都將在4中,反之亦然)。

  • b:你的原始值 - ??? 1?0 ?? 例如
  • x:只是個溫度
  • r:結果

    x =((b >> 2)^(b >> 4))&0x01
    r = b ^((x << 2)|(x << 4))

快速解釋:獲取要查看的兩個位並對它們進行異或,將值存儲到x 通過將此值移回第2位和第4位(以及同時進行“或”運算),您將獲得一個掩碼,當使用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

我沒有對此進行全面測試,但對於少數情況我很快就嘗試了它似乎有效。

這可能沒有優化,但它應該工作:

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;
}

下面的函數將交換位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;
}

我在一個單獨的行上寫了每個操作,以使其更清晰。

#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;
}

假設你的值是x ie,x = ??? 1?0 ??

這個操作可以切換這兩個位:

x = x ^ ((1<<2) | (1<<4));
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.之后,只需要注意你想要進行一位設置操作和一位清除操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM