这不是反转位,而是交换半字节(4 位单元)。换句话说,它将变成:
1100 0101 (abcd efgh)
into:
0101 1100 (efgh abcd)
仅当数据类型实际上是 8 位时才会这样做(否则num << 4
将一些位放置在最右边的八个位的左侧。更安全的方法是确保在移位之前清除所有其他位:
((num & 0xf0) >> 4) | ((num & 0x0f) << 4)
有关按位运算符如何工作的详细信息,请参阅这个优秀的答案 https://stackoverflow.com/questions/1746613/bitwise-operation-and-usage/1746642#1746642.
全位反转的等效表达式,hgfe dcba
,是相当可怕的:
((num & 0x01) << 7)
| ((num & 0x02) << 5)
| ((num & 0x04) << 3)
| ((num & 0x08) << 1)
| ((num & 0x10) >> 1)
| ((num & 0x20) >> 3)
| ((num & 0x40) >> 5)
| ((num & 0x80) >> 7)
它提取并移位八位中的每一位。
还有一些优化可以在一个操作中处理一组不连续的位,例如:
num = ((num & 0xf0) >> 4) | ((num & 0x0f) << 4) // abcdefgh -> efghabcd
num = ((num & 0xcc) >> 2) | ((num & 0x33) << 2) // efghabcd -> ghefcdab
num = ((num & 0xaa) >> 1) | ((num & 0x55) << 1) // ghefcdab -> hgfedcba
这些工作原理是抓取不连续的位并将它们向左或向右移动,掩码值显示哪些位受到影响:
0xf0, 0x0f -> 1111-0000, 0000-1111, shift by 4
0xcc, 0x33 -> 1100-1100, 0011-0011, shift by 2
0xaa, 0x55 -> 1010-1010, 0101-0101, shift by 1
每行中的第一个位掩码提取要右移的位,第二个位掩码抓取要左移的位。然后将两个结果重新组合。以第二个为例,假设你有位abcdefgh
事先评估表达式((num & 0xcc) >> 2) | ((num & 0x33) << 2)
:
(num&0xcc)>>2 (num&0x33)<<2
------------- -------------
abcdefgh abcdefgh
11001100 00110011 'and' with mask
-------- --------
ab00ef00 00cd00gh
00ab00ef cd00gh00 shift right/left
\ /
00ab00ef
cd00gh00 'or' them together
--------
cdabghef
因此,您可以看到位提取、移位和重组操作如何允许您反转值内各部分的顺序:
ab cd ef gh
\ / \ /
X X
/ \ / \
cd ab gh ef
我建议你尝试与第三次操作类似的实验num = ((num & 0xaa) >> 1) | ((num & 0x55) << 1)
,您会看到它也按预期运行,反转每组两个中的各个位。