在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; } 
  1. 将低位移至高位并屏蔽结果位。
  2. 将高位移至低位并屏蔽结果位。
  3. 屏蔽掉所有尚未移动的位。
  4. 将结果与OR结合使用。

码:

 unsigned SwitchBits(unsigned n) { return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666); } 

或者,如果你想要非常聪明。 它可以通过两个较少的操作来完成,但由于一些指令之间的依赖性,这实际上可能不会更快。

  1. 移动高位以与低位对齐
  2. 如果低位为高,则XOR在低位中记录0 ,如果它们不同则为1
  3. 由此,仅屏蔽每个半字节的低位。
  4. 由此,乘以9 ,这将保持低位,并将其复制到高位。
  5. 由此,XOR与原始值。 在高位和低位相同的情况下,不会发生正确的变化。 如果它们不同,它们将被有效地交换。

码:

 unsigned SwitchBits(unsigned n) { return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n; }