26

为什么x86指令INC(递增)和DEC(递减)不影响CFFLAGSREGISTER中的(进位标志)?

4

4 回答 4

38

要了解为什么您可能需要记住当前具有 32 位和 64 位值的“x86”CPU 的生命开始于更有限的 8 位机器,可以追溯到 Intel 8008。(我在 1973 年在这个世界上编码,我仍然记住(呃)它!)。

在那个世界里,寄存器既珍贵又小。您需要INC/DEC用于各种目的,最常见的是循环控制。许多循环涉及执行“多精度算术”(例如,16 位或更多!)通过设置INC/DEC设置零标志 ( Z),您可以使用它们很好地控制循环;通过坚持循环控制指令不改变进位标志CF

一旦你习惯了丑陋的指令集,这工作得很好。

在具有更大字数的更现代的机器上,您不需要太多,因此INC并且DEC可以在语义上等同于ADD...,1 等。事实上,这就是我在需要进位集时使用的:-}

大多数情况下,我现在远离INCDEC因为他们会进行部分条件代码更新,这可能会导致管道中的有趣停顿,并且ADD/SUB不会。因此,在无关紧要的地方(大多数地方),我使用ADD/SUB来避开摊位。我仅在保持代码小问题时才使用INC/ DEC,例如,适合一个或两个指令的大小产生足够差异的高速缓存行。这可能是毫无意义的纳米[字面意思!]-优化,但我的编码习惯相当老派。

我的解释告诉我们为什么INC/DEC设置零标志 ( Z)。INC对于为什么/DEC设置符号(和奇偶校验标志),我没有特别令人信服的解释。

编辑 2016 年 4 月:似乎在现代 x86 上可以更好地处理失速问题。请参阅INC 指令与 ADD 1:这有关系吗?

于 2012-11-17T22:57:47.620 回答
6

当你有由 inc/dec 设置的标志时为什么要签名的问题最好用问题来解决:你宁愿没有选项a吗?

a) for (n=7;n>=0;n--)   // translates to   `dec + jns`
b) for (n=8;n>0;n--)    // translates to   `dec + jnz`

正如Ira Baxter已经澄清的那样,进位标志用于许多算法——不仅是多精度算术,而且还用于单色/cga/EGA 时代的位图处理:这会将 80 像素宽的行向右移动一个像素......

        mov cx, 10
begin:  lodsb
        rcr al,1   // this is rotate though carry:
        stosb      // for the algorithm to work, carry must not be destroyed
        LOOP begin //

但后来:为什么要平价?

我相信答案是为什么不。该指令集来自 70 年代后期,当时晶体管稀缺。拒绝为某些特定指令计算奇偶校验标志没有任何意义,只会增加 CPU 的复杂性。

于 2012-11-24T16:28:21.357 回答
2
  1. 指令incdec通常用于维护迭代或循环计数。使用 32 位,迭代次数可高达 4,294,967,295。这个数字对于大多数应用来说已经足够大了。如果我们需要比这更大的计数怎么办?我们必须使用 add 而不是 inc 吗?这就引出了第二个也是主要的原因。

  2. 进位标志检测到的条件也可以通过零标志检测。为什么?因为 inc 和 dec 仅将数字更改 1。例如,假设 ECX 寄存器已达到其最大值 4,294,967,295 (FFFFFFFFH)。如果我们然后执行

                     inc ECX
    

    我们通常期望进位标志设置为 1。但是,我们可以通过注意 ECX = 0 来检测这种情况,这会设置零标志。因此,设置进位标志对于这些指令来说确实是多余的。

于 2018-07-08T16:58:23.533 回答
-1

因为不需要影响。检查零标志就足够了。因此,在 inc 和 dec 指令之后,进位标志保持不变,在某些情况下这很有用。

于 2012-11-17T23:12:50.677 回答