了解有关i ++和i = i + 1的更多信息
我想知道两种增量forms之间是否存在差异。 一些链接说i ++比i = i + 1更快;
另外作为人之一,我的观察对于汇编代码也是一样的。 请检查图像,其中汇编代码对于i ++和i = i + 1都是相同的 –
还有另一个链接说以前曾经是真的,增量运算符比加法和赋值更快,但现在编译器优化i ++和i = i + 1相同。
是否有任何官方文件/文件我们可以参考确认什么是正确的? (我通常会使用信用卡和一个人在stackoverflow上接受的答案数量。在我提供的链接上找不到任何此类信息)。
实际上,如果你使用C ++,那么习惯于编写++i
会好得多。 原因很简单: i++
需要副本。
a = ++i; // a is set to the result of i+1 a = i++; // make a copy of i, compute i+1, save the copy of i in a
如果没有优化,汇编代码将如下所示:
a = ++i; a = i++; MOV eax, (i) MOV eax, (i) PUSH eax ADD eax, 1 ADD eax, 1 MOV (i), eax MOV (i), eax POP eax MOV (a), eax MOV (a), eax
现在,通过优化,结果在C中是相同的,其中++
运算符仅适用于整数和指针。
++
和--
是因为大多数处理器在写入C时都有INC
和DEC
指令。 因此,如果您要使用索引寄存器,则会应用以下指令:
char a[256]; ...init 'a' in some way... int sum =0; for(int i = 0; i < 100; ++i) { sum += a[i]; }
这可以通过简单的INC
来完成,如(6502)中所述:
LDA #00 LDY #00 LOOP: CLC ADC ($80),Y INY <-- ++i or i++ CPY #100 BCC LOOP
请注意,在C中我们有另一种表示法来增加变量:
i += 1;
如果您需要将寄存器增加1以上,这是实用的:
i += 3;
或者每次加倍注册:
i += i; // (equivalent to i *= 2; or i <<= 1; in C++)
问题:为什么INC
和DEC
不能与所有80x86一起使用?
曾经有一段时间ADD reg, 1
和SUB reg, 1
指令比INC reg
和DEC reg
更快。 在过去,它更快,因为指令更小,我们没有缓存(或非常少)。 今天,两种指令可能大致相同。
从下面的评论来看,“缓慢”的原因是FLAGS注册:
英特尔优化参考,第3.5.1.1节使用INC和DEC指令
从另一个更新的评论来看,英特尔文档中引用的缓慢似乎已在较新的处理器中得到修复。 因此,如果事先知道,这些指令的使用或不使用应取决于目标处理器。
正如phresnel在评论中指出的那样,对于很多人来说, i++
和++i
之间的差异可能并不明显。 对于整数,优化实际上是微不足道的,即使使用-O0也肯定会发生。 但是,在C ++中,这是一个不同的故事。 有一个类都有两个增量运算符,清楚地表明i++
需要一个副本(即使data_
只是一个整数,但在这种情况下你也可以这样做: return data_++
- 它仍然需要一个隐藏得很好的副本!) :
class A { public: A& operator ++ () // ++i -- no copy { ...apply the ++ operation to 'data_'... return *this; // return a reference to this } A operator ++ (int) // i++ -- needs a temporary copy { // remember that the 'int' is totally ignored in the function, // its only purpose is to distinguish '++i' from 'i++' A copy = *this; // here we need a copy ++*this; return copy; // and here we return said copy } private: some_type_t data_; };
请注意,现代C ++编译器不会在i++
函数中生成两个副本,因为可以优化返回值,而无需额外的副本。
如果使用i++
,如果在C ++中i ++和++ i之间存在性能差异,那么两种情况之间的差异可以显示得明显更慢? (菲涅耳提到的链接)
没有官方文件。 c规范没有声明i ++必须比i + 1更快,因此编译器/优化器可以自由地做他们喜欢的事情(并且他们可以根据周围的代码和优化级别做出不同的选择)。
我使用i ++是因为我阅读速度更快,错误输入的字符更少。
在两者之间使用代码分析器,对于当前版本的gcc编译器,i ++和i = i + 1都是相同的。 这完全取决于编译器优化。
如果您具体谈论处理器,您可以看到下面的机器周期图表,
INC – 增量
Usage: INC dest Modifies flags: AF OF PF SF ZF Adds one to destination unsigned binary operand. Clocks Size Operands 808x 286 386 486 Bytes reg8 3 2 2 1 2 reg16 3 2 2 1 1 reg32 3 2 2 1 1 mem 15+EA 7 6 3 2-4 (W88=23+EA)
ADD – 算术加法
Usage: ADD dest,src Modifies flags: AF CF OF PF SF ZF Adds "src" to "dest" and replacing the original contents of "dest". Both operands are binary. Clocks Size Operands 808x 286 386 486 Bytes reg,reg 3 2 2 1 2 mem,reg 16+EA 7 7 3 2-4 (W88=24+EA) reg,mem 9+EA 7 6 2 2-4 (W88=13+EA) reg,immed 4 3 2 1 3-4 mem,immed 17+EA 7 7 3 3-6 (W88=23+EA) accum,immed 4 3 2 1 2-3
您可以找到针对各种处理器ADD和INC的机器周期,8086,80286,80386,80486,以上,您可以在英特尔处理器手册中找到这些内容。 降低机器周期的响应速度。
RMV = 10;
rmv = rmv ++; // rmv + 1都是相同的
的printf( “1.时间=%d”,RMV);
//输出是10比第二时间增量10 + 1所以,值是11
printf(“2.time =%d”,rmv ++); //值为11