C 字节中的位反转是如何工作的?

C 字节中的位反转是如何工作的?,c,bit-manipulation,bitwise-operators,bit-shift,or-operator,C,Bit Manipulation,Bitwise Operators,Bit Shift,Or Operator,我是编程新手,我发现这种方法可以在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) >

我是编程新手,我发现这种方法可以在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位与最低有效4位。然后,它将两个最高阶对交换在一起,将最低阶对交换在一起;最后,它进行2n和2n+1位的成对交换

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

<76543210>
第一次手术中没有

&0xF0-> &0x0F-> 现在前者右移4位,后者左移4位,我们得到

>> 4 -> 最后,这些是or'ed在一起,因此在语句之后

b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b的值是原始位的排列

在第二条语句中,掩码0xCC在二进制中为11001100,0x33在二进制中为00110011;中间值为:

&0xCC>>2->>2->;和 &0x33。 这两个“或”组合在一起将导致排列。最后,掩码0xAA是二进制的10101010,0x55是01010101。因此,我们有

&0xAA>>1->>1->;和 &0x55
这些“或”组合在一起将导致与原来相反的排列。

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

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

<76543210>
第一次手术中没有

&0xF0-> &0x0F-> 现在前者右移4位,后者左移4位,我们得到

>> 4 -> 最后,这些是or'ed在一起,因此在语句之后

b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b的值是原始位的排列

在第二条语句中,掩码0xCC在二进制中为11001100,0x33在二进制中为00110011;中间值为:

&0xCC>>2->>2->;和 &0x33。 这两个“或”组合在一起将导致排列。最后,掩码0xAA是二进制的10101010,0x55是01010101。因此,我们有

&0xAA>>1->>1->;和 &0x55
这些或加在一起将导致与原始数字相反的排列。

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

0xF0: 11110000
0x0F: 00001111

0xCC: 11001100
0x33: 00110011

0xAA: 10101010
0x55: 01010101
第一对数字用于屏蔽和交换字节的前4位和后4位

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


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

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

0xF0: 11110000
0x0F: 00001111

0xCC: 11001100
0x33: 00110011

0xAA: 10101010
0x55: 01010101
第一对数字用于屏蔽和交换字节的前4位和后4位

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


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

因此它只是大量的比特移位。位的顺序如下:

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:

第三行与另一个掩码0B10101010和0b01010101相同,分别为10325476:

最后,我们采取行动:

76543210 => 01234567

所以这只是一个很大的变化。位的顺序如下:

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:

第三行与另一个掩码0B10101010和0b01010101相同,分别为10325476:

最后,我们采取行动:

76543210 => 01234567
让我们按如下方式对b中的位进行编号:

01234567
二进制中的0xF0为11110000,0x0F为00001111。第一个赋值将最左边的4位向右移位,最右边的4位向左移位,然后将它们与OR组合,因此结果为:

45670123
67452301
76543210
0xCC是11001100,0x33是00110011。当这些屏蔽位移位2位并组合时,结果为:

45670123
67452301
76543210
最后,0xAA是10101010,0x55是01010101。完成这些遮罩和移位后,结果是:

45670123
67452301
76543210
瞧!这是牧师 旧秩序

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

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

01234567
二进制中的0xF0为11110000,0x0F为00001111。第一个赋值将最左边的4位向右移位,最右边的4位向左移位,然后将它们与OR组合,因此结果为:

45670123
67452301
76543210
0xCC是11001100,0x33是00110011。当这些屏蔽位移位2位并组合时,结果为:

45670123
67452301
76543210
最后,0xAA是10101010,0x55是01010101。完成这些遮罩和移位后,结果是:

45670123
67452301
76543210
瞧!这是相反的顺序


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

为了理解上述代码的含义,您需要了解4个主要方面

&和位运算符。 |或按位运算符。 >>右移操作员。
为了理解上述代码的含义,您需要了解4个主要方面

&和位运算符。 |或按位运算符。 >>右移操作员。
将常数转换成二进制,看看它们的意思。这将交换4位的组,然后交换2位,然后交换1位。首先,比特7654和3210。然后是7632和5410。然后是7531和6420。写这篇文章让我意识到,如果不指出:PStep通过调试器中的函数,在每条语句后以二进制形式打印b,就很难解释了。然后你会被启发。将常数转换成二进制,看看它们的意思。这将交换4位的组,然后交换2位,然后交换1位。首先,比特7654和3210。然后是7632和5410。然后是7531和6420。写这篇文章让我意识到,如果不指出:PStep通过调试器中的函数,在每条语句后以二进制形式打印b,就很难解释了。然后你就会开悟。