了解有关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时都有INCDEC指令。 因此,如果您要使用索引寄存器,则会应用以下指令:

 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++) 

问题:为什么INCDEC不能与所有80x86一起使用?

曾经有一段时间ADD reg, 1SUB reg, 1指令比INC regDEC 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