Skip to content

PF

在标志寄存器中,PF (Parity Flag) 被称为 奇偶标志位。

它是标志寄存器里比较特殊的一个,因为它的关注点非常“狭窄”且具有深厚的“历史感”。理解它只需要记住两点:只看低 8 位 和 数“1”的个数。


一、 PF 的基本规则

PF 记录运算结果的【最低 8 位】中,二进制位为 “1” 的个数是奇数还是偶数。

  • PF = 1:表示低 8 位中 “1” 的个数为 偶数 (Even)。
  • PF = 0:表示低 8 位中 “1” 的个数为 奇数 (Odd)。

记忆口诀:Parity is 1 if bits are Even(偶一奇零)。


二、 关键细节

1. 只看最低 8 位(LSB)

这是初学者最容易忽略的地方。即使你是在做 64 位(RAX)或 32 位(EAX)的运算,PF 仅仅取决于结果的最后 8 位,高位有多少个“1”完全不影响 PF。

  • 例子:
    • 结果是 0x0001 (二进制 ...0000 0001):低8位有 1 个“1”,奇数 \(\to\) PF = 0。
    • 结果是 0x0101 (二进制 ...0001 0001):低8位有 2 个“1”,偶数 \(\to\) PF = 1。
    • 结果是 0xFF01:虽然总共有 9 个“1”,但低 8 位是 01,只有 1 个“1” \(\to\) PF = 0。

2. 哪些指令会影响它?

绝大多数算术运算(ADD, SUB, INC, DEC)和逻辑运算(AND, OR, XOR, TEST)都会根据结果设置 PF。MOV 指令通常不会改变 PF。


三、 实战演示

让我们用几行代码模拟一下:

mov al, 3       ; 3 的二进制是 0000 0011 (2个“1”,偶数)
add al, 0       ; 加上 0,结果不变,触发标志位更新
; 此时 PF = 1

mov al, 7       ; 7 的二进制是 0000 0111 (3个“1”,奇数)
add al, 0       ; 触发标志位更新
; 此时 PF = 0

四、 如何根据 PF 跳转?

在汇编中,有两个专门针对 PF 的跳转指令:

  1. JP / JPE (Jump if Parity / Jump if Parity Even):当 PF = 1(偶数)时跳转。
  2. JNP / JPO (Jump if No Parity / Jump if Parity Odd):当 PF = 0(奇数)时跳转。

五、 为什么会有这个标志位?(历史背景)

你可能会觉得:“我写程序为什么要关心‘1’的个数是奇数还是偶数啊?”

这其实是一个历史遗留产物: * 早期通信:在 70-80 年代,计算机之间通过串口发送数据非常容易出错(受到电磁干扰)。 * 奇偶校验(Parity Check):为了检测数据在传输过程中是否变异,人们会在数据后面补一个位。如果接收方发现“1”的个数不对,就知道数据坏了。 * 硬件支持:当时的 CPU(如 8080/8086)在硬件层面提供这个标志位,是为了让程序员能快速进行这种简单的错误检查,而不需要写复杂的算法去数“1”的个数。


六、 现代开发中 PF 还有用吗?

在现代的应用程序开发(如 Windows/Linux 上的普通软件)中,PF 极少被用到。

但在以下特殊领域,它依然存在: 1. 底层驱动/通信协议:处理一些古老的串行端口(RS-232)通信。 2. 加密/哈希算法:某些特殊的位运算优化。 3. 逆向工程/破解:有时候开发者会利用 PF 这种冷门的标志位来做一些奇特的逻辑判断,以此混淆代码,增加破解难度。

总结

  • PF = 结果低 8 位里 “1” 的个数。
  • 偶数个 1 \(\to\) PF=1。
  • 奇数个 1 \(\to\) PF=0。
  • 现状:知道它代表“奇偶性”即可,实际编程中用得远没有 ZF (零) 和 CF (进位) 多。