在汇编语言中,CF(Carry Flag,进位/借位标志)通常与加减法相关:加法产生进位、减法产生借位时,CF 会被置位,但很多初学者会注意到一个看似矛盾的现象:执行 AND 这样的逻辑指令时,CF 位居然也会发生变化,更准确地说,在 x86 架构中,AND 指令会无条件把 CF 清零。
按位与运算本身并不涉及“进位”,为什么 AND 会影响 CF 位呢?

先看现象:AND 对 CF 的实际影响
在 x86 汇编中,以下代码可以清楚地展示 AND 对 CF 的影响:
stc ; CF = 1
mov al, 0F0h ; AL = 1111 0000
mov bl, 0CCh ; BL = 1100 1100
and al, bl ; AL = 0F0h AND 0CCh = 0C0h
; 结果:AL = 1100 0000
; CF = 0,OF = 0
可以看到,在执行 AND 之前,我们通过 STC 指令把 CF 置为 1,执行 AND 之后,CF 变成了 0,也就是说,AND 并不是“保留 CF 原值”,而是主动清除了 CF。
根据 Intel 和 AMD 的手册,AND 指令对标志位的影响是:
- CF = 0
- OF = 0
- SF、ZF、PF 根据运算结果设置
- AF 未定义
不仅是 AND,OR、XOR、TEST 等逻辑运算指令也会清零 CF 和 OF,这说明它是 x86 逻辑运算类指令的一个共同设计。
直觉上的矛盾:按位与不产生进位
从纯数学或逻辑运算的角度看,AND 是一个按位操作:
1111 0000 & 1100 1100 ------------ 1100 0000
它只关心每一位之间的“与”关系,并不存在像加法那样的从低位到高位的进位传播,按位与运算本身并不会产生“进位”。
既然没有进位产生,为什么 CF 会变化?
这里的关键是:CF 是一个硬件标志位,它的值并不一定只能来自运算产生的进位,CPU 设计者可以规定它在某类指令后固定为 0 或 1。AND 对 CF 的影响,本质上是一种指令集架构层面的规定。
原因一:指令集架构规定逻辑指令清除 CF
在 x86 架构中,标志位的更新规则属于指令集架构的一部分,Intel/AMD 明确规定:逻辑运算指令执行后,CF 和 OF 清零。
为什么要这样规定?
一个重要原因是:为编程提供一个确定、可预测的行为。
假设 CPU 在执行 AND 时保留 CF 的旧值,那么程序员在阅读汇编代码时,就必须时刻记住 CF 之前是什么,而硬件也需要额外电路或微操作来“保持 CF 不变”,相比之下,直接清零 CF 更简单,也更容易理解。
从架构设计角度看:
AND影响 CF,并不是因为按位与运算产生了进位,而是因为指令集规定逻辑运算后 CF 必须清零。
这与 CLC 指令类似,只不过 AND 在清 CF 的同时还会改变结果和其他标志位。
原因二:硬件实现上,逻辑运算不经过进位链
从 CPU 硬件实现的角度看,ALU 通常有多个功能,
- 加法
- 减法
- 与运算
- 或运算
- 异或运算
在加法或减法运算中,ALU 会使用进位链,最高位的进位输出会连接到 CF 标志位。
执行 ADD 时:
CF = 最高位的进位输出
执行 SUB 时:
CF = 最高位的借位输出
但是在执行 AND、OR、XOR 等逻辑运算时,ALU 使用的是按位逻辑门,不经过加法器的进位链,此时并不存在一个自然的“进位输出”。
硬件设计者面临一个问题:逻辑运算后,CF 应该写入什么值?
有几种选择:
- 保持旧值不变;
- 写入一个固定值,0;
- 写入某个与运算相关的值。
其中第 1 种需要额外电路来阻止标志寄存器更新,增加复杂度,第 3 种没有自然对应物,第 2 种最简单:直接把 CF 输入固定为 0,然后和其他标志位一起写入标志寄存器。
所以在很多 x86 CPU 实现中,执行逻辑运算时,ALU 的进位输出会被强制为 0,这个 0 被写入 CF,AND 后 CF 总是被清零。
可以这样理解:
加法运算是“计算产生 CF”,而逻辑运算是“硬件把 CF 置为 0”。
实际编程中的意义与注意事项
AND 可以顺便清 CF
因为 AND 会清 CF,所以在某些场景下,它可以同时完成数据操作和进位标志复位。
and eax, eax ; 测试 EAX 是否为 0,CF=0、OF=0
不过如果仅仅为了清 CF,通常更推荐使用专门的 CLC 指令,因为 AND 会改变其他标志位,可能不是你的本意。
小心多精度运算中的 CF 被破坏
如果需要依赖 CF 进行多精度加减法,插入逻辑指令时要特别小心。
cmp eax, ebx ; 比较 EAX 和 EBX,CF 可能为 0 或 1 test ecx, ecx ; 测试 ECX,但 CF 被清零! adc edx, 0 ; 这里的 CF 已经不是前面 CMP 的借位结果
在上面的例子中,TEST 会清 CF,导致后面的 ADC 使用了错误的进位值,这是汇编编程中常见的坑之一。
如果需要保留 CF,可以调整指令顺序,或者使用 PUSHF / POPF 等指令保存和恢复标志寄存器。
AND 对 CF 是清零,不是“计算进位”
初学者容易误解为“AND 某两个数后,CF 根据某种进位关系设置”,实际上没有这种关系,无论操作数是什么,AND 后 CF 都是 0。
mov al, 0FFh and al, 0FFh ; AL = 0FFh,CF 仍然为 0
即使两个操作数全是 1,也不会让 CF 置位。
AND 会影响 CF 位,并不是因为按位与运算产生了进位,而是因为 x86 架构规定:逻辑运算指令执行后,CF 和 OF 清零。
从硬件角度看,逻辑运算不经过加法器的进位链,ALU 在执行 AND 时没有自然的进位输出,为了简化设计并提供确定的行为,CPU 直接把 CF 置为 0。
准确地说:
AND对 CF 的影响是“无条件清零”,而不是“根据结果设置”。
理解这一点,对编写汇编程序、调试底层代码,以及理解 CPU 标志位机制都非常重要。
