[英]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中,反之亦然)。
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
是要交換的整數, a
和b
是要交換的位的位置(索引),從較低有效位開始計數,從零開始計數。
使用你的例子( n = ???1?0??
),你可以按如下方式調用函數:
swap_bits(n, 2, 4);
理由 :如果它們不同,你只需要交換這些位(這就是為什么r != s
)。 在這種情況下,其中一個是1而另一個是0.之后,只需要注意你想要進行一位設置操作和一位清除操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.