在int的每个半字节中切换位
如何仅使用位操作(无控制结构)将每个半字节的第0位和第3位切换为整数? 为了解决这个问题,我需要创建什么样的面具? 任何帮助,将不胜感激。 例如,8(1000)变为1(0001)。
/* * SwitchBits(0) = 0 * SwitchBits(8) = 1 * SwitchBits(0x812) = 0x182 * SwitchBits(0x12345678) = 0x82a4c6e1 * Legal Operations: ! ~ & ^ | + <> */ int SwitchBits(int n) { }
码:
#include #include static uint32_t SwitchBits(uint32_t n) { uint32_t bit0_mask = 0x11111111; uint32_t bit3_mask = 0x88888888; uint32_t v_bit0 = n & bit0_mask; uint32_t v_bit3 = n & bit3_mask; n &= ~(bit0_mask | bit3_mask); n |= (v_bit0 << 3) | (v_bit3 >> 3); return n; } int main(void) { uint32_t i_values[] = { 0, 8, 0x812, 0x12345678, 0x9ABCDEF0 }; uint32_t o_values[] = { 0, 1, 0x182, 0x82A4C6E1, 0x93B5D7F0 }; enum { N_VALUES = sizeof(o_values) / sizeof(o_values[0]) }; for (int i = 0; i < N_VALUES; i++) { printf("0x%.8" PRIX32 " => 0x%.8" PRIX32 " (vs 0x%.8" PRIX32 ")\n", i_values[i], SwitchBits(i_values[i]), o_values[i]); } return 0; }
输出:
0x00000000 => 0x00000000 (vs 0x00000000) 0x00000008 => 0x00000001 (vs 0x00000001) 0x00000812 => 0x00000182 (vs 0x00000182) 0x12345678 => 0x82A4C6E1 (vs 0x82A4C6E1) 0x9ABCDEF0 => 0x93B5D7F0 (vs 0x93B5D7F0)
注意使用uint32_t
来避免带有符号整数的符号位的未定义行为。
要获得一点,您可以使用AND将其屏蔽掉。 要获得最低位,例如:
x & 0x01
想想AND如何工作:必须设置两个位。 由于我们与1进行AND运算,除第一个之外的所有位必须为0,因为它们在0x01中为0。 最低位将为0或1,具体取决于x
; 换句话说,最低位将是x
的最低位,这正是我们想要的。 视觉:
x = abcd AND 1 = 0001 -------- 000d
(其中abcd
代表那些插槽中的位;我们不知道它们是什么)
要将它移动到位3的位置,只需将其移动:
(x & 0x01) << 3
视觉上,再次:
x & 0x01 = 000d << 3 ----------- d000
要添加它,首先,我们需要清除x
那个位置。 我们再次使用AND:
x & ~0x08
在这里,我们反转0x08
(二进制为1000):这意味着除了第 3位以外的所有位都被设置,当我们和x
,除了该位之外我们得到x
。
在视觉上,
0x08 = 1000 (invert) ----------- 0111 AND x = abcd ------------ 0bcd
与OR结合:
(x & ~0x08) | ((x & 0x01) << 3)
在视觉上,
x & ~0x08 = 0bcd | ((x & 0x01) << 3) = d000 -------------------------- dbcd
现在,这只将位0移动到位3,并且只是覆盖位3.我们仍然需要执行位3→0。这只是另一个:
x & 0x08 >> 3
我们需要清除它的位置:
x & ~0x01
我们可以结合两个清算部分:
x & ~0x09
然后:
(x & ~0x09) | ((x & 0x01) << 3) | ((x & 0x08) >> 3)
那当然只处理最低的半字节。 我将把其他人留作练习。
试试下面的代码。 在这里你应该知道按位运算符来实现和纠正位置。还需要了解维护,移动和切换基本属性。
#include #define BITS_SWAP(x) x=(((x & 0x88888888)>>3) | ((x & 0x11111111)<<3)) | ((x & ~ (0x88888888 | 0x11111111))) int main() { int data=0; printf("enter the data in hex=0x"); scanf("%x",&data); printf("bits=%x",BITS_SWAP(data)); return 0; }
OP
vinay @ vinay-VirtualBox:〜/ c_skill $ ./a.out
以hex=0x1
输入数据
bits=8
vinay @ vinay-VirtualBox:〜/ c_skill $ ./a.out
以hex=0x812
输入数据hex=0x812
bits=182
vinay @ vinay-VirtualBox:〜/ c_skill $ ./a.out
以hex=0x12345678
输入数据hex=0x12345678
bits=82a4c6e1
维奈@维奈 - VirtualBox的:〜/ c_skill $
尝试xor swap的这个变种:
uint32_t switch_bits(uint32_t a){ static const mask = 0x11111111; a ^= (a & mask) << 3; a ^= (a >> 3) & mask; a ^= (a & mask) << 3; return a; }
- 将低位移至高位并屏蔽结果位。
- 将高位移至低位并屏蔽结果位。
- 屏蔽掉所有尚未移动的位。
- 将结果与OR结合使用。
码:
unsigned SwitchBits(unsigned n) { return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666); }
或者,如果你想要非常聪明。 它可以通过两个较少的操作来完成,但由于一些指令之间的依赖性,这实际上可能不会更快。
- 移动高位以与低位对齐
- 如果低位为高,则XOR在低位中记录
0
,如果它们不同则为1
。 - 由此,仅屏蔽每个半字节的低位。
- 由此,乘以
9
,这将保持低位,并将其复制到高位。 - 由此,XOR与原始值。 在高位和低位相同的情况下,不会发生正确的变化。 如果它们不同,它们将被有效地交换。
码:
unsigned SwitchBits(unsigned n) { return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n; }