文章目录
- [🧩 基础背景](#🧩 基础背景)
- [⚙️ 分析逐步讲解](#⚙️ 分析逐步讲解)
-
- [🧠 1️⃣ 定义变量 a、b](#🧠 1️⃣ 定义变量 a、b)
- [🧩 2️⃣ 按位与(AND)](#🧩 2️⃣ 按位与(AND))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧩 3️⃣ 按位或(OR)](#🧩 3️⃣ 按位或(OR))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧩 4️⃣ 按位异或(XOR)](#🧩 4️⃣ 按位异或(XOR))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧩 5️⃣ 按位取反(NOT)](#🧩 5️⃣ 按位取反(NOT))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧩 6️⃣ 左移(SHL)](#🧩 6️⃣ 左移(SHL))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧩 7️⃣ 右移(SHR)](#🧩 7️⃣ 右移(SHR))
-
- [➤ 执行过程:](#➤ 执行过程:)
- [➤ 结果:](#➤ 结果:)
- [➤ 汇编解释:](#➤ 汇编解释:)
- [🧾 汇总表](#🧾 汇总表)
- [🧠 编译器生成逻辑分析](#🧠 编译器生成逻辑分析)
- [✅ 总结要点](#✅ 总结要点)
位运算代码
c
#include <iostream>
#include <bitset>
void basicBitOperations() {
unsigned int a = 0b11001100; // 204
unsigned int b = 0b10101010; // 170
//std::cout << "a = " << std::bitset<8>(a) << " (" << a << ")" << std::endl;
//std::cout << "b = " << std::bitset<8>(b) << " (" << b << ")" << std::endl;
// 位与运算
unsigned int andResult = a & b;
//std::cout << "a & b = " << std::bitset<8>(andResult) << " (" << andResult << ")" << std::endl;
// 位或运算
unsigned int orResult = a | b;
//std::cout << "a | b = " << std::bitset<8>(orResult) << " (" << orResult << ")" << std::endl;
// 位异或运算
unsigned int xorResult = a ^ b;
//std::cout << "a ^ b = " << std::bitset<8>(xorResult) << " (" << xorResult << ")" << std::endl;
// 位非运算
unsigned int notResult = ~a;
//std::cout << "~a = " << std::bitset<8>(notResult) << " (" << notResult << ")" << std::endl;
// 左移运算
unsigned int leftShift = a << 2;
//std::cout << "a << 2 = " << std::bitset<8>(leftShift) << " (" << leftShift << ")" << std::endl;
// 右移运算
unsigned int rightShift = a >> 2;
//std::cout << "a >> 2 = " << std::bitset<8>(rightShift) << " (" << rightShift << ")" << std::endl;
}
int main()
{
basicBitOperations();
}
汇编代码
c
--- D:\ReverseEngineering\CPP_Code\位运算\位运算\位运算.cpp -----------------------------
1: #include <iostream>
2: #include <bitset>
3:
4: void basicBitOperations() {
002A1820 push ebp
002A1821 mov ebp,esp
002A1823 sub esp,120h
002A1829 push ebx
002A182A push esi
002A182B push edi
002A182C lea edi,[ebp-60h]
002A182F mov ecx,18h
002A1834 mov eax,0CCCCCCCCh
002A1839 rep stos dword ptr es:[edi]
002A183B mov ecx,offset _3428AB1E_位运算\位运算\位运算@cpp (02AC079h)
002A1840 call @__CheckForDebuggerJustMyCode@4 (02A1325h)
002A1845 nop
5: unsigned int a = 0b11001100; // 204
002A1846 mov dword ptr [a],0CCh
6: unsigned int b = 0b10101010; // 170
002A184D mov dword ptr [b],0AAh
7:
8: //std::cout << "a = " << std::bitset<8>(a) << " (" << a << ")" << std::endl;
9: //std::cout << "b = " << std::bitset<8>(b) << " (" << b << ")" << std::endl;
10:
11: // 位与运算
12: unsigned int andResult = a & b;
002A1854 mov eax,dword ptr [a]
002A1857 and eax,dword ptr [b]
002A185A mov dword ptr [andResult],eax
13: //std::cout << "a & b = " << std::bitset<8>(andResult) << " (" << andResult << ")" << std::endl;
14:
15: // 位或运算
16: unsigned int orResult = a | b;
002A185D mov eax,dword ptr [a]
002A1860 or eax,dword ptr [b]
002A1863 mov dword ptr [orResult],eax
17: //std::cout << "a | b = " << std::bitset<8>(orResult) << " (" << orResult << ")" << std::endl;
18:
19: // 位异或运算
20: unsigned int xorResult = a ^ b;
002A1866 mov eax,dword ptr [a]
002A1869 xor eax,dword ptr [b]
002A186C mov dword ptr [xorResult],eax
21: //std::cout << "a ^ b = " << std::bitset<8>(xorResult) << " (" << xorResult << ")" << std::endl;
22:
23: // 位非运算
24: unsigned int notResult = ~a;
002A186F mov eax,dword ptr [a]
002A1872 not eax
002A1874 mov dword ptr [notResult],eax
25: //std::cout << "~a = " << std::bitset<8>(notResult) << " (" << notResult << ")" << std::endl;
26:
27: // 左移运算
28: unsigned int leftShift = a << 2;
002A1877 mov eax,dword ptr [a]
002A187A shl eax,2
002A187D mov dword ptr [leftShift],eax
29: //std::cout << "a << 2 = " << std::bitset<8>(leftShift) << " (" << leftShift << ")" << std::endl;
30:
31: // 右移运算
32: unsigned int rightShift = a >> 2;
002A1880 mov eax,dword ptr [a]
002A1883 shr eax,2
002A1886 mov dword ptr [rightShift],eax
33: //std::cout << "a >> 2 = " << std::bitset<8>(rightShift) << " (" << rightShift << ")" << std::endl;
34: }
002A1889 pop edi
002A188A pop esi
002A188B pop ebx
002A188C add esp,120h
002A1892 cmp ebp,esp
002A1894 call __RTC_CheckEsp (02A1249h)
002A1899 mov esp,ebp
002A189B pop ebp
002A189C ret
分析
非常好 👏
你这段代码展示了 C++ 编译后,编译器如何将每一种位运算 (&
, |
, ^
, ~
, <<
, >>
)翻译为底层汇编指令。
我们来逐行剖析 C 代码 ↔ 汇编指令 ↔ 实际寄存器行为 ↔ 位级变化。
🧩 基础背景
源代码:
cpp
unsigned int a = 0b11001100; // 204 (0xCC)
unsigned int b = 0b10101010; // 170 (0xAA)
unsigned int andResult = a & b;
unsigned int orResult = a | b;
unsigned int xorResult = a ^ b;
unsigned int notResult = ~a;
unsigned int leftShift = a << 2;
unsigned int rightShift = a >> 2;
在汇编中:
- 变量
a
、b
等都分配在函数栈上。 - 每次操作都是
mov → 运算 → mov
三步。 - 寄存器使用
EAX
(主运算寄存器)。
⚙️ 分析逐步讲解
🧠 1️⃣ 定义变量 a、b
asm
002A1846 mov dword ptr [a],0CCh ; a = 0xCC (204)
002A184D mov dword ptr [b],0AAh ; b = 0xAA (170)
变量 | 二进制 | 十进制 | 十六进制 |
---|---|---|---|
a | 11001100 | 204 | 0xCC |
b | 10101010 | 170 | 0xAA |
这两行只是往栈上保存常数,没有计算。
🧩 2️⃣ 按位与(AND)
asm
002A1854 mov eax,dword ptr [a]
002A1857 and eax,dword ptr [b]
002A185A mov dword ptr [andResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | 载入 a → EAX = 11001100b |
2️⃣ | 与 b 做 AND → EAX = 11001100 AND 10101010 = 10001000 |
3️⃣ | 保存结果到 andResult |
➤ 结果:
10001000b = 0x88 = 136
➤ 汇编解释:
and eax, [b]
是逐位逻辑与。- 对每一位:1 & 1 → 1,否则 0。
- 常用于 屏蔽(mask)操作。
🧩 3️⃣ 按位或(OR)
asm
002A185D mov eax,dword ptr [a]
002A1860 or eax,dword ptr [b]
002A1863 mov dword ptr [orResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | OR b → 11001100 OR 10101010 = 11101110 |
3️⃣ | 保存结果 |
➤ 结果:
11101110b = 0xEE = 238
➤ 汇编解释:
or eax, [b]
:任一位为 1 → 结果为 1。- 用于 强制开启特定位,如 "设置标志位"。
🧩 4️⃣ 按位异或(XOR)
asm
002A1866 mov eax,dword ptr [a]
002A1869 xor eax,dword ptr [b]
002A186C mov dword ptr [xorResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | XOR b → 11001100 XOR 10101010 = 01100110 |
3️⃣ | 保存结果 |
➤ 结果:
01100110b = 0x66 = 102
➤ 汇编解释:
-
xor eax, [b]
:相同为 0,不同为 1。 -
特性:
x ^ 0 = x
x ^ x = 0
-
常见技巧:
xor eax, eax
用来清零寄存器。
🧩 5️⃣ 按位取反(NOT)
asm
002A186F mov eax,dword ptr [a]
002A1872 not eax
002A1874 mov dword ptr [notResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | NOT → 每一位取反 → 00110011 |
3️⃣ | 保存结果 |
➤ 结果:
00110011b = 0x33 = 51
➤ 汇编解释:
not eax
:1 → 0,0 → 1。- 用于 按位反转。
- 不影响标志位(ZF/SF/CF 不变)。
🧩 6️⃣ 左移(SHL)
asm
002A1877 mov eax,dword ptr [a]
002A187A shl eax,2
002A187D mov dword ptr [leftShift],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100b |
2️⃣ | 左移 2 位 → 00110000b |
3️⃣ | 保存结果 |
➤ 结果:
00110000b = 0x30 = 48
➤ 汇编解释:
shl eax, 2
:逻辑左移 2 位。- 左移时 高位溢出 → CF,低位补 0。
- 相当于:
a * 2² = a * 4
。 - 常用于乘 2 的幂。
🧩 7️⃣ 右移(SHR)
asm
002A1880 mov eax,dword ptr [a]
002A1883 shr eax,2
002A1886 mov dword ptr [rightShift],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100b |
2️⃣ | 右移 2 位 → 00110011b |
3️⃣ | 保存结果 |
➤ 结果:
00110011b = 0x33 = 51
➤ 汇编解释:
shr eax, 2
:逻辑右移 2 位。- 低位移出 → CF;高位补 0。
- 相当于:
a / 4
(对无符号数)。
🧾 汇总表
操作 | C 表达式 | 汇编指令 | 结果(二进制) | 十进制 | 说明 |
---|---|---|---|---|---|
AND | a & b | and eax,[b] |
10001000 |
136 | 按位与,清零特定位 |
OR | a | b | or eax,[b] |
11101110 |
238 |
XOR | a ^ b | xor eax,[b] |
01100110 |
102 | 按位异或,反转不同位 |
NOT | ~a | not eax |
00110011 |
51 | 取反 |
SHL | a << 2 | shl eax,2 |
00110000 |
48 | 左移(×4) |
SHR | a >> 2 | shr eax,2 |
00110011 |
51 | 右移(÷4) |
🧠 编译器生成逻辑分析
在汇编层,所有这些操作都遵循相同模板:
mov eax, [变量1]
<位运算指令> eax, [变量2或立即数]
mov [结果变量], eax
也就是三步:
1️⃣ 载入源操作数。
2️⃣ 执行位级运算。
3️⃣ 存回结果。
由于这些是 单指令逻辑操作(单周期执行) ,
它们在 CPU 中都由 ALU(算术逻辑单元) 直接完成。
✅ 总结要点
类型 | 汇编指令 | 操作特性 |
---|---|---|
逻辑运算 | and , or , xor , not , test |
不涉及进位,纯二进制位逻辑 |
移位运算 | shl , shr , sar , rol , ror |
位移动与标志控制 |
ALU 执行单元 | 硬件电路级并行完成 | 比加减更快 |
标志位变化 | ZF , SF , CF , PF 更新(NOT 不影响) |
用于分支和条件判断 |