1

我是编程新手,我发现这种方法可以在 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;
}

由用户发布以回答此问题,但我不明白它是如何工作的。这些常数是什么意思?

4

5 回答 5

5

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

0xF0: 11110000
0x0F: 00001111

0xCC: 11001100
0x33: 00110011

0xAA: 10101010
0x55: 01010101

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

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

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

于 2017-03-17T21:02:39.430 回答
2

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


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

<76543210>

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

  • <76543210> & 0xF0-><7654oooo>
  • <76543210> & 0x0F-><oooo3210>

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

  • <7654oooo> >> 4-><oooo7654>
  • <oooo3210> << 4-><3210oooo>

最后,这些被或在一起,因此在语句之后

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

的值b是原始位的排列<32107654>

在第二个语句中,掩码0xCC11001100二进制的,并且0x3300110011二进制的;中间值为:

  • (<32107654> & 0xCC) >> 2-> <32oo76oo> >> 2-> <oo32oo76>; 和
  • (<32107654> & 0x33) << 2-> <oo10oo54> << 2-> <10oo54oo>

这些 2 or'ed 一起将导致 permutation <10325476>。现在最后,掩码0xAA10101010二进制的,并且0x5501010101. 因此我们有

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

这些或'ed在一起将导致<01234567>与原始相反的排列。

于 2017-03-17T21:01:37.737 回答
1

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

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
于 2017-03-17T21:06:10.740 回答
0

b让我们按如下方式对位进行编号:

01234567

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

45670123

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

67452301

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

76543210

瞧!这是相反的顺序。

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

于 2017-03-17T21:06:26.530 回答
0

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

  1. & (AND) Bitwise Operator.
  2. | (OR) Bitwise Operator.
  3. >> (Right Shift Operator).
  4. << (Left Shift Operator).

幸运的是,我刚刚写了一篇详细的博客,解释了有关数字系统和位操作的所有内容

于 2017-04-06T11:19:08.837 回答