“4 - 12”和“4 + (-12)”有什么区别?
What is the difference between “4 - 12” and “4 + (-12)”?
我尝试比较下一个表达式:
1)
mov al, 4
mov bl, 12
sub al, bl ; CF == 1
0000 0100 (4)
+
1111 0100 (-12)
=
1111 1000 (-8 == 248)
2)
mov al, 4
mov bl, -12
add al, bl ; CF == 0
0000 0100 (4)
+
1111 0100 (-12)
=
1111 1000 (-8 == 248)
结果相同,但进位标志不同。为什么?通过二进制补码加法实现的减法
x86 上的减法不等于二进制补码的加法。要了解进位标志将假定的值,您必须改为执行长减法:
0000 0100
- 0000 1100
-------------
1 1111 1000
看看最后怎么还剩下借位?这个借位是设置进位标志的东西(即进位等于借位)。
像 ARM 这样的一些其他架构确实将减法作为加法来实现,但它们不是作为二进制补码的加法,而是作为一个补码的加法和一个额外的进位。这在减去 0 时很重要.
例如,您的方法将产生 12 − 0:
0000 1100
+ 0000 0000 (- 0000 0000 => + 0000 0000)
-------------
0 0000 1100
有明确的进位。但实际发生的是
0000 1100
+ 1111 1111 (- 0000 0000 => +1111 1111 + 1)
+ 1
-------------
1 0000 1100
带进位。这个细节很重要,否则与 0 的比较将无法正常工作。在这个方案中,只要没有借位就表示进位(即进位补借位)。
Intel 的做法和 ARM 的做法实际上总是产生相同的结果,只是进位标志正好相反。因此,只要 ARM 设置进位,Intel 就会清除它,反之亦然。
这两种减法语义的方法都相当普遍。 ARM 方法稍微更容易实现,因为它允许直接使用加法器进行减法,而无需接触进位。使用 Intel 方法,在执行减法时必须对进位进位和进位出位进行补充,但这样做的额外门在宏伟的计划中并不重要。另一方面,英特尔的方法对程序员来说更直观,因为如果您将正在执行的操作可视化为长减法,那么将进位标志也视为借位更有意义。
我尝试比较下一个表达式:
1)
mov al, 4
mov bl, 12
sub al, bl ; CF == 1
0000 0100 (4)
+
1111 0100 (-12)
=
1111 1000 (-8 == 248)
2)
mov al, 4
mov bl, -12
add al, bl ; CF == 0
0000 0100 (4)
+
1111 0100 (-12)
=
1111 1000 (-8 == 248)
结果相同,但进位标志不同。为什么?通过二进制补码加法实现的减法
x86 上的减法不等于二进制补码的加法。要了解进位标志将假定的值,您必须改为执行长减法:
0000 0100
- 0000 1100
-------------
1 1111 1000
看看最后怎么还剩下借位?这个借位是设置进位标志的东西(即进位等于借位)。
像 ARM 这样的一些其他架构确实将减法作为加法来实现,但它们不是作为二进制补码的加法,而是作为一个补码的加法和一个额外的进位。这在减去 0 时很重要.
例如,您的方法将产生 12 − 0:
0000 1100
+ 0000 0000 (- 0000 0000 => + 0000 0000)
-------------
0 0000 1100
有明确的进位。但实际发生的是
0000 1100
+ 1111 1111 (- 0000 0000 => +1111 1111 + 1)
+ 1
-------------
1 0000 1100
带进位。这个细节很重要,否则与 0 的比较将无法正常工作。在这个方案中,只要没有借位就表示进位(即进位补借位)。
Intel 的做法和 ARM 的做法实际上总是产生相同的结果,只是进位标志正好相反。因此,只要 ARM 设置进位,Intel 就会清除它,反之亦然。
这两种减法语义的方法都相当普遍。 ARM 方法稍微更容易实现,因为它允许直接使用加法器进行减法,而无需接触进位。使用 Intel 方法,在执行减法时必须对进位进位和进位出位进行补充,但这样做的额外门在宏伟的计划中并不重要。另一方面,英特尔的方法对程序员来说更直观,因为如果您将正在执行的操作可视化为长减法,那么将进位标志也视为借位更有意义。