【问题标题】:How does this bits reversion in a byte work?这个字节中的位反转如何工作?
【发布时间】:2017-08-09 13:37:12
【问题描述】:

我是编程新手,我发现这种方法可以在 C 中反转字节中的位:

//(10000011) -> (11000001)

unsigned char reverse(unsigned char b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
   return b;
}

一位用户在回复this question 时发布,但我不明白它是如何工作的。这些常数是什么意思?

【问题讨论】:

  • 将常量转换为二进制看看它们的含义。
  • 这会相互交换 4 位组,然后是 2 位,然后是 1。所以首先,位 7654 和 3210。然后,7632 和 5410。然后,7531 和 6420。写这个让我意识到不指出就不容易解释:P
  • 在调试器中单步执行函数,在每条语句后以二进制形式打印b。然后你就会得到启发。

标签: c bit-manipulation bitwise-operators bit-shift or-operator


【解决方案1】:

查看上述数字的二进制表示可能会有所帮助:

0xF0: 11110000
0x0F: 00001111

0xCC: 11001100
0x33: 00110011

0xAA: 10101010
0x55: 01010101

第一对数字用于屏蔽和交换一个字节的前 4 位和后 4 位。

第二对屏蔽掉并交换一组 4 位的前 2 位和后 2 位。

第三对屏蔽并交换相邻的位对。

【讨论】:

    【解决方案2】:

    代码首先交换“半字节”,即最高有效 4 位与最低有效 4 位。然后它将两个最高订单对交换在一起,并将底部对交换在一起;最后它会进行 2n 和 2n+1 位的成对交换。


    我将在这里用它们的指数在尖括号中表示b的原始值的位(这只是我在这里使用的伪符号,不是正确的C) ;我使用o 来标记任何始终为 0 的位。所以一开始我们有

    <76543210>
    

    在我们的第一个操作中没有

    • &lt;76543210&gt; &amp; 0xF0 -> &lt;7654oooo&gt;
    • &lt;76543210&gt; &amp; 0x0F -> &lt;oooo3210&gt;

    现在前者右移4位,后者左移4位,因此我们得到

    • &lt;7654oooo&gt; &gt;&gt; 4 -> &lt;oooo7654&gt;
    • &lt;oooo3210&gt; &lt;&lt; 4 -> &lt;3210oooo&gt;

    最后这些是或'ed在一起,因此在语句之后

    b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
    

    b 的值是原始位的排列&lt;32107654&gt;

    在第二个语句中,掩码0xCC 是二进制的110011000x33 是二进制的00110011;中间值是:

    • (&lt;32107654&gt; &amp; 0xCC) &gt;&gt; 2 -> &lt;32oo76oo&gt; &gt;&gt; 2 -> &lt;oo32oo76&gt;;和
    • (&lt;32107654&gt; &amp; 0x33) &lt;&lt; 2 -> &lt;oo10oo54&gt; &lt;&lt; 2 -> &lt;10oo54oo&gt;.

    这 2 个或一起将导致排列 &lt;10325476&gt;。最后,掩码0xAA 是二进制的101010100x5501010101。因此我们有

    • (&lt;10325476&gt; &amp; 0xAA) &gt;&gt; 1 -> &lt;1o3o5o7o&gt; &gt;&gt; 1 -> &lt;o1o3o5o7&gt;;和
    • (&lt;10325476&gt; &amp; 0x55) &lt;&lt; 1 -> &lt;o0o2o4o6&gt; &lt;&lt; 1 -> &lt;0o2o4o6o&gt;

    这些或'ed 在一起将导致排列 &lt;01234567&gt; 与原来的相反。

    【讨论】:

      【解决方案3】:

      所以这只是很多位移。位的顺序如下:

      76543210
      

      现在,第一行,第一部分保留高位,将低位设置为 0(掩码为 0b11110000),将它们向右移动 4。第二部分对低位执行相同的操作(掩码为 0b00001111),然后向左移动:

      first line, first part:  7654xxxx => xxxx7654 (bits shift to the right)
      first line, second part: xxxx3210 => 3210xxxx (bits shift to the left)
      add them together:                => 32107654
      

      然后,第二行。相同的操作,不同的掩码(分别为 0b11001100 和 0b00110011),32107654

      second line, first part:  32xx76xx => xx32xx76 (bits shift to the right)
      second line, second part: xx10xx54 => 10xx54xx (bits shift to the left)
      add them together:                 => 10325476
      

      第三行与其他掩码相同(分别为 0b10101010 和 0b01010101),10325476

      third line, first part:  1x3x5x7x => x1x3x5x7 (bits shift to the right)
      third line, second part: x0x2x4x6 => 0x2x4x6x (bits shift to the left)
      add them together:                => 01234567
      

      所以我们最终以行动结束:

      76543210 => 01234567
      

      【讨论】:

        【解决方案4】:

        让我们将b 中的位编号如下:

        01234567
        

        0xF0 二进制是111100000x0F00001111。第一个赋值将最左边的 4 位向右移动,最右边的 4 位向左移动,然后将它们与OR 组合,所以结果是:

        45670123
        

        0xCC110011000x3300110011。当这些被屏蔽的位移动2位并组合时,结果是:

        67452301
        

        最后,0xAA101010100x5501010101。当这些掩码和移位完成后,结果是:

        76543210
        

        瞧!这是相反的顺序。

        请注意,对于每一对移位,位掩码是相互反转的,并且被移位的位数与掩码中 1 位序列的长度相同。所以它们中的每一个都在交换大小为该序列长度的比特组。

        【讨论】:

          【解决方案5】:

          您需要了解 4 个主要内容才能理解上述代码的含义。

          1. &amp; (AND) Bitwise Operator.
          2. | (OR) Bitwise Operator.
          3. &gt;&gt; (Right Shift Operator).
          4. &lt;&lt; (Left Shift Operator).

          幸运的是,我刚刚写了一篇详细的博客,解释了有关 Number System and Bit Manipulation 的所有内容

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-04-15
            • 2011-06-22
            • 1970-01-01
            • 2021-07-12
            • 1970-01-01
            • 1970-01-01
            • 2017-07-24
            • 2016-11-13
            相关资源
            最近更新 更多