为什么x86指令INC
(递增)和DEC
(递减)不会影响FLAGSREGISTER中的CF
(进位标志)?
答案 0 :(得分:29)
要理解为什么你可能需要记住当前的“x86”具有32位和64位值的CPU开始使用更多有限的8位机器,返回到英特尔8008.(我在1973年的世界编码,我还记得(呃)它!)。
在那个世界里,登记册很珍贵。出于各种目的,您需要INC
/ DEC
,最常见的是循环控制。许多循环涉及进行“多精度算术”(例如,16位或更多!)通过让INC
/ DEC
设置零标志(Z
),您可以使用它们来控制循环很好;通过坚持循环控制指令不改变进位标志(CF
),进位在循环迭代中保留,并且您可以实现多精度操作而无需编写大量代码来记住进位状态。
一旦你习惯了丑陋的指令集,这个效果非常好。
在字体较大的更现代的机器上,您不需要这么多,因此INC
和DEC
在语义上等同于ADD
...,1等。事实上,这就是我在需要随身携带时使用的内容: - }
大多数情况下,我现在远离INC
和DEC
,因为他们会进行部分条件代码更新,这会导致管道中出现有趣的停顿,ADD
/ {{1 }} 别。因此,无关紧要(大多数地方),我使用SUB
/ ADD
来避免失速。我只在保持代码较小的情况下才使用SUB
/ INC
,例如,适合缓存行,其中一条或两条指令的大小会产生足够的差异。这可能是毫无意义的纳米[字面意思!] - 优化,但我在编码习惯上相当老派。
我的解释告诉我们为什么DEC
/ INC
设置了零标志(DEC
)。我没有特别引人注目的解释为什么Z
/ INC
设置了标志(以及奇偶校验标志)。
编辑2016年4月:似乎在现代x86上处理失速问题更好。见INC instruction vs ADD 1: Does it matter?
答案 1 :(得分:5)
当你有一个由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已经阐明的那样,Carry标志用于许多算法 - 不仅是多精度算术,而且还用于单色/ 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的复杂性。
答案 2 :(得分:1)
inc 和 dec 指令通常用于维护迭代或循环计数。使用32位,迭代次数可以高达4,294,967,295。对于大多数应用而言,此数字足够大。如果我们需要一个大于此的计数怎么办?我们必须使用add代替inc吗?这是第二个也是最主要的原因。
由进位标志检测的条件也可以由零标志检测。为什么?因为inc和dec仅将数字更改1。例如,假设ECX寄存器已达到最大值4,294,967,295(FFFFFFFFH)。如果然后执行
inc ECX
我们通常希望将进位标志设置为1。但是,我们可以通过注意到ECX = 0(将零标志设置为零)来检测这种情况。因此,对于这些指令,设置进位标志确实是多余的。
答案 3 :(得分:-1)
因为没有必要影响。检查Zero标志就足够了。 因此,在inc和dec指令之后,进位标志保持不变,在某些情况下这是有用的。