了解有关i ++和i = i + 1的更多信息

时间:2014-10-05 04:19:09

标签: c++ c assembly optimization post-increment

我想知道两种增量形式之间是否存在差异。一些links说i ++比i = i + 1更快;

同样作为一个人,我的观察对于汇编代码也是一样的。请检查图像,其中汇编代码对于i ++和i = i + 1都是相同的 - enter image description here

还有另一个link说以前曾经是真的,增量运算符比加法和赋值更快,但现在编译器优化i ++和i = i + 1相同。

是否有任何官方文件/文件我们可以参考确认什么是正确的? (我通常会使用信用卡和一个人在stackoverflow上接受的答案数量。在我提供的链接上找不到任何此类信息。)

4 个答案:

答案 0 :(得分:15)

实际上,如果你使用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注册:

Intel Optimization Reference, section 3.5.1.1 Use of the INC and DEC Instructions

从另一个更新的评论来看,英特尔文档中引用的缓慢似乎已在较新的处理器中得到修复。因此,如果事先知道,这些指令的使用或不使用应取决于目标处理器。


正如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++函数中生成两个副本,因为可以优化返回的值,而无需额外的副本。

如果使用Is there a performance difference between i++ and ++i in C++?(phresnel提到的链接)中描述的i++,两种情况之间的差异可能会明显变慢

答案 1 :(得分:5)

没有官方文件。 c规范没有声明i ++必须比i + 1更快,因此编译器/优化器可以自由地做他们喜欢的事情(他们可以根据周围的代码和优化级别做出不同的选择)。

我使用i ++是因为我阅读速度更快,错误输入的字符更少。

答案 2 :(得分:3)

在两者之间使用代码分析器,对于当前版本的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,以上,您可以在英特尔处理器手册中找到。降低机器周期的响应速度。

答案 3 :(得分:-1)

RMV = 10;

rmv = rmv ++; // rmv + 1都相同

的printf( “1.时间=%d”,RMV);

//输出是10比第二时间增量10 + 1所以,值是11

printf(“2.time =%d”,rmv ++); //值为11