【问题标题】:Why the carry flag is set in this substitution equation?为什么在这个替换方程中设置进位标志?
【发布时间】:2017-09-01 15:28:24
【问题描述】:

在这个article 中,它说:

1111 + 0001 = 0000(进位标志开启)

据我所知,当结果不适合特定数量的位(本例中为 4 位)时会发生进位,因此上述等式确实导致了进位(因为结果有效10000 , 不适合 4 位)。


但请看同一篇文章中的以下内容:

0000 - 0001 = 1111 (carry flag is turned on)

我不明白为什么在这种情况下设置进位标志,我的意思是结果是1111,所以它适合4位!

【问题讨论】:

  • 1111+0001=0000翻译成十进制就是:(-1) + 1 = 0,第一位是进位标志,后三位从0到7(0000到0111)计数或从 -8 到 -1(1000 到 1111)。
  • x86 的进位标志表示减法时借位。
  • 相关(不重复,加上这是我的回答):stackoverflow.com/questions/45261231/…,请参阅底部进位标志的讨论
  • 这个问题已经被问过很多次了……

标签: assembly x86 twos-complement


【解决方案1】:

如果你忽略类型的大小,那么

1111 + 0001 = 10000

这就是为什么你得到一个进位(只是表示结果大于存储的0)。如果您必须添加额外的(十六进制)“数字”,这一点很重要。


通过减法,你可以得到类似的问题:

0000 - 0001 = 1111

这实际上是说:0 - 1 = 15。这不是真的,所以进位被设置为表示执行了借位,即或多或少地执行了以下操作:

10000 - 0001 = 1111 (16 - 1 = 15)

当你用十进制减去时你做同样的事情:

    34
    18
  ---- -

要从 4 中减去 8,您必须从下一位借位 1,以得到 14 − 8 = 6。需要借位才能正确减去下一对高位数字。 3 - 1 = 2,但你也必须减去借位,所以现在 3 - 1 - 借位 = 1。这就是为什么你(正确地)得到 16 而不是 26 的结果。

    34
    18
  ---- -
    16

二进制借位具有相同的功能:它存储在进位标志中并且可以使用SBB(借位减法)而不是普通的SUB(减法)进行减法(例如在x86汇编程序中)。进位标志的值(现在用作“借用标志”)从两个操作数中额外减去:

Value1  DW      0x1234  ; alternatively: DB 0x34,0x12
Value2  DW      0x0678  ;                DB 0x78,0x06  
Result  DW      0

        MOV     AL,BYTE PTR [Value1]      ; 0011 0100
        SUB     AL,BYTE PTR [Value2]      ; 0111 1000
        MOV     BYTE PTR [Result],AL      ; 0xBC = 1011 1100, but a borrow was needed!
        MOV     AL,BYTE PTR [Value1 + 1]  ; 0001 0010
        SBB     AL,BYTE PTR [Value2 + 1]  ; 0000 0110 (0x12 - 0x06 - carry = 0x0B)
        MOV     BYTE PTR [Result + 1],AL  ; 0x0B = 0000 1011 

【讨论】:

  • 但是 x86 中的减法不是通过加法完成的吗(我们将第二个数字反转并加一,然后我们将这两个数字相加)?
  • @user8240761:嗯?你从哪里得到这个想法的?减法只是通过减法完成。好的,这是如何在 CPU 内部完成的(如果有额外的减法硬件或只是加法器硬件来获取否定数据)我不知道,但对于我们这些 CPU 用户来说,这是一个真正的减法,带有借。所以我写的适用。
  • 我在很多地方读到,为什么选择二进制补码在计算机中表示整数的原因之一是您可以使用相同的逻辑(通过加法)进行加法和减法。跨度>
  • 好吧,我想我明白了,就像你所说的,作为程序员,我们不应该考虑如何在 CPU 内部进行减法运算,我们应该简单地假设减法运算就像我们在“现实生活中所做的那样” "(通过减去而不是通过添加!)。所以如果我们在做减法时需要借位,就会设置进位标志,对吗?
  • 正如我所说,这在内部如何完成并不重要。这个问题有一个x86标签,所以我指的是x86系列的处理器,对于我们这些CPU用户来说,结果就像是做了一个纯减法。但确实 -A = ~A + 1,因此将第二个操作数取反,然后将其加一将得到相同的结果。但同样,对于我们这些 x86 CPU 的用户来说,这并不重要。
【解决方案2】:

在大多数 CPU(包括 x86 CPU)上,进位标志在 加法和减法中的行为方式如下:

进位标志是将数字的“长度”扩展一位时结果的最高位。

例子:

 1110 +  0011 = 01110 + 00010 (extending 4 bits to 5 bits)
01110 + 00011 = 10001 (5 bit result)
 1110 +  0011 =  0001, Carry=1 (highest of the 5 bits is the carry flag)

 0010 -  0011 = 00010 - 00010 (extending 4 bits to 5 bits)
00010 - 00011 = 11111 (5 bit result)
 0010 -  0011  = 1111, Carry=1 (highest of the 5 bits is the carry flag)

(但是,有些 CPU 的进位标志在减法上的表现不同;例如:历史悠久的 6502)

【讨论】:

    【解决方案3】:

    我们从小学就知道 a - b = a + (-b) 并且我们知道使用二进制补码来否定某些东西意味着反转和加一。有些人知道处理器不会减去它们而是添加所以

      0000
     -0001
    =======
    

    真的

          1
       0000
    +  1110
    ========
    

    反转并添加一个,因为无论如何我们都必须进行,所以我们在那里添加一个 而不是做额外的工作。所以我们反转进位并且在进入加法器的过程中反转第二个操作数。

      00001
       0000
    +  1110
    ========
       1111
    

    答案是正确的,但有些处理器会反转进位,听起来您正在使用的处理器就是这样做的。为什么?因为如果您检查其他一些数字集,您会发现该位可以用作借位或不借位,而不是无符号溢出,这对于无符号数字意味着什么,如本例所示。 0000 + 1111 = 1111 这不是无符号溢出。

    因此,从一种架构到另一种架构(ARM、MIPS、AVR、x86 等),如果您想使用该标志(而不是 MIPS),请阅读文档,或者进行实验,因为文档不是很好这个话题。有时,带进位的加法或带借位的减法指令会暗示架构的工作方式(在减法的过程中反转进位标志)。

    【讨论】:

    • 很好的答案,很高兴指出并非所有 ISA 都适用于此。我找到了描述它的英特尔 x86 文档:SBB (sub with borrow) 手册说 CF 的输入值用作借用输入:DEST ← (DEST – (SRC + CF));。它还说:处理器评估这两种数据类型的结果,并设置 OF 和 CF 标志以分别指示有符号或无符号结果中的借位。
    【解决方案4】:

    所以你说这个方程...

    0000 - 0001 = 1111 (carry flag is on)
    

    ...设置进位标志?

    是的,因为在进行加法时会在数据溢出时设置进位! 在减法运算的情况下,进位标志是Borrow标志。

    正如您在Intels 8085 Programming Guide 中看到的,减法补充了进位标志!

    How "SBB" works explained in Intel's 8085 Programming Guide!

    该等式不产生进位,但由减法补充! 希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-23
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多