在int的每个半字节中切换位

时间:2014-03-03 07:02:56

标签: c bit-manipulation

如何仅使用位操作(无控制结构)将每个半字节的第0位和第3位切换为整数?为了解决这个问题,我需要创建什么样的面具?任何帮助,将不胜感激。例如,8(1000)变为1(0001)。

/* 
 * SwitchBits(0) = 0
 * SwitchBits(8) = 1
 * SwitchBits(0x812) = 0x182
 * SwitchBits(0x12345678) = 0x82a4c6e1
 * Legal Operations: ! ~ & ^ | + << >>
 */
int SwitchBits(int n) { 

}

5 个答案:

答案 0 :(得分:2)

代码:

#include <stdio.h>
#include <inttypes.h>

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来避免带有符号整数的符号位的未定义行为。

答案 1 :(得分:1)

要获得一点,您可以使用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)

那当然只处理最低的半字节。我将把其他人留作练习。

答案 2 :(得分:1)

尝试以下代码。在这里你应该知道按位运算符来实现和纠正位置。还需要了解维护,转移和切换基本属性。

 #include<stdio.h>
 #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中输入数据 bits=182

vinay @ vinay-VirtualBox:〜/ c_skill $ ./a.out

hex=0x12345678中输入数据 bits=82a4c6e1

维奈@维奈-VirtualBox的:〜/ c_skill $

答案 3 :(得分:1)

  1. 将低位移至高位并屏蔽掉结果位。
  2. 将高位移至低位并屏蔽掉结果位。
  3. 屏蔽掉所有尚未移动的位。
  4. 将结果与OR结合使用。
  5. 代码:

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

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

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

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

答案 4 :(得分:1)

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