假设我有一个六位未知值的字节:
???1?0??
我想交换第2位和第4位的比特位(不改变任何?
的值):
???0?1??
但我如何在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);
编辑:关于位的翻转,还有一些信息。
当你使用异或运算符(^
)把两个整数值相互异或时,异或运算将在位级别上执行,就像这样:
for each (bit in value 1 and value 2)
result bit = value 1 bit xor value 2 bit
目的是让第一个值的第0位和第二个值的第0位做异或运算,第1位和第二个值的第1位以此类推。异或操作不会影响值中的其他位。实际上,它是在多个位上进行了并行位异或。
观察异或的真值表,你会发现用'1'对一个位进行异或操作可以有效地切换该位的状态。
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
因此,要切换位1和3,请写一个二进制数,在您想要切换位的位置放置1,在您想要保留值不变的位置放置0:
00001010
转换为十六进制:0x0a。您可以切换任意数量的位:
0x39 = 00111001
将切换位0、3、4和5
使用位操作符无法在单个指令中“交换”两个比特(即交换它们的位置,而不是值)。
如果您真的想要交换它们,最佳方法可能是使用查找表。对于许多“棘手”的转换,这一点也适用。
BYTE lookup[256] = {/* left this to your imagination */};
for (/*all my data values */)
newValue = lookup[oldValue];
x
中。通过将此值向后移动到位2和4(并进行OR运算),您可以获得一个掩码,当与b
进行XOR运算时,将交换您的两个原始位。下表显示了所有可能的情况。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
x
为1),则翻转位(有效地交换它们),否则保持不变(这与交换它们相同,因为它们是相同的)。 - Nathan Fellmanunsigned 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;
}
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;
}
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。之后,只需注意您想要执行一次位设置操作和一次位清除操作。假设你的值是x,即x=???1?0??
这个操作可以切换这两个位:
x = x ^ ((1<<2) | (1<<4));
#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;
}