“将 NEG 指令应用于非零操作数始终设置进位标志”是什么意思。
为什么从 1 中减去 2 会设置进位标志?
00000001 (1)
+ 11111110 (-2) [in 2-complement form]
---------------------
CF:1 11111111 (-1) [ why is the carry flag set here???]
您可以将NEG a
其视为等效于SUB 0, a
. 如果a
非零,那么这将设置进位标志(因为这总是会导致无符号溢出)。
首先,我们知道什么时候a < b
,a - b
总是可以产生一个进位(借)。
其次,让我们了解为什么x86在减法时会反转进位标志。
第一点对于人类来说是如此明显,但对于计算机而言并非如此。(假设用电脑a + (~b+1)
来代替a - b
做计算。)电脑怎么算出有借?我们可以将 2 的补码作为时钟。(顺时针表示原数 -- a
,逆时针表示倒数 -- ~b+1
)
所以对于计算机来说,它可以告诉(用于减法)如果a > b
,a + ~b + 1
将有进位(图中重叠);如果a < b
,a + ~b + 1
将没有进位(图中的间隙)。
结论:
所以对于减法,如果没有进位,则表示有借位;如果有进位意味着没有借位,即反转进位位。
顺便说一句,据我尝试,没有溢出(即OF
未设置when 1 - 2
。)我不认为@Oliver 在这一点上是正确的。
在阅读 CF 标志是如何定义的那一刻之前,还不清楚。英特尔 CPU 文档手册说:
If the result of an arithmetic operation is treated as an unsigned integer,
the CF flag indicates an out-of-range condition
否定任何被视为无符号的东西显然是无效的,因为没有无符号值可以翻转其符号并且仍然保持无符号(除非它为零)。因此,尽管使用铅笔和纸的方法,您会得到完全相反的结果:否定零时的“铅笔进位 = 1”和否定任何其他位模式时的“铅笔进位 = 0”。
可能这就是为什么我们在标志寄存器中有“进位标志”而不是“进位位”的原因。再次 - 进位标志表明操作数(视为无符号)的操作结果超出特定位数的允许“无符号范围”。
如果您否定的值被视为已签名 - 您应该查看溢出标志。
这里的关键点是:'carry FLAG' 不是 'carry BIT'。它有时像一个人一样,但并非总是如此。
顺便说一句:并不是只有 x86/64 可以做到这一点。例如在 Atmel 的 AVR 中也是如此。
ARM 可能会这样做,因为他们的手册说:
For a subtraction, including the comparison instruction CMP and the negate
instructions NEGS and NGCS, C is set to 0 if the subtraction produced a
borrow (that is, an unsigned underflow), and to 1 otherwise.
通常,ARM 的文档调用进位标志 -进位/借位标志,因此不应将其视为进位位
只要结果不能用无符号二进制数表示,就会在减法中设置进位标志。无符号数始终被视为正数。
1 - 2
给出的结果将以无符号 8 位格式表示-1
但-1
不能表示,因此设置了进位标志。
即使减法算法的结果适合 8 位,即使该结果可以解释为具有正确结果的 2 补码二进制数,也会发生这种情况。
该NEG
指令旨在与将被解释为 2 补码数字的数字一起使用,因为该指令所做的正是对该数字进行 2 补码,即更改其符号。符号是 2 补数的属性,而不是无符号数的属性。
NEG n
与计算相同0-n
,这里唯一适合无符号 8 位数的结果是00000000
. 任何其他结果都不是正确的无符号数。