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

时间:2021-12-08 13:45:57

I was wondering if there is difference between the two forms of increment. Some of the links says i++ is faster that i=i+1;

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

Also as one of the person my observation is also the same for assembly code. please check the image where both the assembly code are same for i++ and i=i+1 - 了解有关i ++和i = i + 1的更多信息

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

There is another link that says that it used to be true previously that increment operator was faster than addition and assignment, but now compilers optimize i++ and i=i+1 the same.

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

Is there any official document/paper which we can refer to confirm what is exactly right ? (I usually go with credit's and number of accepted answers of a person on *. Could't find any such thing on the links I provided).

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

4 个解决方案

#1


15  

Actually, if you do C++, it is much better to get used to write ++i instead. The reason is simple: i++ requires a copy.

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

Without optimizations, the assembly code would look like this:

如果没有优化,汇编代码将如下所示:

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

Now, with optimizations, the result is the same in C where the ++ operator only applies to integers and pointers.

现在,通过优化,结果在C中是相同的,其中++运算符仅适用于整数和指针。

The ++ and -- are there because most processors had an INC and a DEC instruction at the time C was written. So if you were to use an index register, these instructions would be applied:

++和 - 是因为大多数处理器在写入C时都有INC和DEC指令。因此,如果您要使用索引寄存器,则会应用以下指令:

char a[256];
...init 'a' in some way...
int sum =0;
for(int i = 0; i < 100; ++i)
{
    sum += a[i];
}

This could be done with a simple INC as in (6502):

这可以通过简单的INC来完成,如(6502)中所述:

    LDA #00
    LDY #00
LOOP:
    CLC
    ADC ($80),Y
    INY              <-- ++i or i++
    CPY #100
    BCC LOOP

Note that in C we have another notation to increment a variable:

请注意,在C中我们有另一种表示法来增加变量:

i += 1;

This is practical if you need to increment the register by more than 1:

如果您需要将寄存器增加1以上,这是实用的:

i += 3;

Or to double the register each time:

或者每次加倍注册:

i += i;   // (equivalent to  i *= 2;  or  i <<= 1;  in C++)

Question: Why is INC and DEC not used with all 80x86?

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

There has been time when the ADD reg, 1 and SUB reg, 1 instructions were faster than the INC reg and DEC reg. In the old days, it was faster because the instruction was smaller and we had no cache (or very little). Today, either instruction is probably about the same.

曾经有一段时间ADD reg,1和SUB reg,1指令比INC reg和DEC reg更快。在过去,它更快,因为指令更小,我们没有缓存(或非常少)。今天,两种指令可能大致相同。

From a comment below, a reason for the "slowness" was the FLAGS register:

从下面的评论来看,“缓慢”的原因是FLAGS注册:

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

英特尔优化参考,第3.5.1.1节使用INC和DEC指令

From another, more current comment, it looks like the slowness referenced in that Intel document has been fixed in newer processors. So the use or non-use of these instructions should depend on the target processor if known in advance.

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


As pointed out by phresnel in a comment, the difference between i++ and ++i was probably not clear for many people. For an integer, the optimization is really trivial and will most certainly happen even with -O0. However, in C++, that's a different story. There is a class with both increment operators clearly showing that a copy is required for i++ (even if data_ is just an integer, although in that case you could also do: return data_++ -- it still requires a well hidden copy!):

正如phresnel在评论中指出的那样,对于很多人来说,i ++和++ i之间的差异可能并不明显。对于整数,优化实际上是微不足道的,即使使用-O0也肯定会发生。但是,在C ++中,这是一个不同的故事。有一个类都有两个增量运算符,清楚地表明i ++需要一个副本(即使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_;
};

Note that modern C++ compilers do not make two copies in the i++ function as the returned value can be optimized out without the need of an extra copy.

请注意,现代C ++编译器不会在i ++函数中生成两个副本,因为可以优化返回值,而无需额外的副本。

The difference between both cases can be shown as clearly slower if using i++ as described in Is there a performance difference between i++ and ++i in C++? (link mentioned by phresnel)

如果使用i ++,如果在C ++中i ++和++ i之间存在性能差异,那么两种情况之间的差异可以显示得明显更慢? (菲涅耳提到的链接)

#2


5  

There is no official document. The c spec does not declare that i++ must be faster than i+1 so compilers/optimizers are free to do what they like (and they can make different choices based on surrounding code and optimization level).

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

I use i++ because it's faster for me to read, with fewer characters to mistype.

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

#3


3  

Runthe code profiler between both of them it will be same for both i++ and i = i+1 for current version of gcc compiler. This purely depends on the compiler optimizations.

在两者之间使用代码分析器,对于当前版本的gcc编译器,i ++和i = i + 1都是相同的。这完全取决于编译器优化。

If you speak about processor specifically you can see the below chart for machine cycles,

如果您具体谈论处理器,您可以看到下面的机器周期图表,

INC - Increment

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 - Arithmetic Addition

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

You can find the machine cycles taken for each instruction ADD and INC for various processors, 8086, 80286, 80386, 80486,above, you can find this documented in intel processor manuals. Lower the machine cycles faster the response.

您可以找到针对各种处理器ADD和INC的机器周期,8086,80286,80386,80486,以上,您可以在英特尔处理器手册中找到这些内容。降低机器周期的响应速度。

#4


-1  

rmv=10;

rmv=rmv++;//rmv+1 both are same

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

printf("1.time=%d",rmv);

//output is 10 than second time increment 10+1 so,value is11

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

printf("2.time=%d",rmv++);//value is 11

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

#1


15  

Actually, if you do C++, it is much better to get used to write ++i instead. The reason is simple: i++ requires a copy.

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

Without optimizations, the assembly code would look like this:

如果没有优化,汇编代码将如下所示:

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

Now, with optimizations, the result is the same in C where the ++ operator only applies to integers and pointers.

现在,通过优化,结果在C中是相同的,其中++运算符仅适用于整数和指针。

The ++ and -- are there because most processors had an INC and a DEC instruction at the time C was written. So if you were to use an index register, these instructions would be applied:

++和 - 是因为大多数处理器在写入C时都有INC和DEC指令。因此,如果您要使用索引寄存器,则会应用以下指令:

char a[256];
...init 'a' in some way...
int sum =0;
for(int i = 0; i < 100; ++i)
{
    sum += a[i];
}

This could be done with a simple INC as in (6502):

这可以通过简单的INC来完成,如(6502)中所述:

    LDA #00
    LDY #00
LOOP:
    CLC
    ADC ($80),Y
    INY              <-- ++i or i++
    CPY #100
    BCC LOOP

Note that in C we have another notation to increment a variable:

请注意,在C中我们有另一种表示法来增加变量:

i += 1;

This is practical if you need to increment the register by more than 1:

如果您需要将寄存器增加1以上,这是实用的:

i += 3;

Or to double the register each time:

或者每次加倍注册:

i += i;   // (equivalent to  i *= 2;  or  i <<= 1;  in C++)

Question: Why is INC and DEC not used with all 80x86?

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

There has been time when the ADD reg, 1 and SUB reg, 1 instructions were faster than the INC reg and DEC reg. In the old days, it was faster because the instruction was smaller and we had no cache (or very little). Today, either instruction is probably about the same.

曾经有一段时间ADD reg,1和SUB reg,1指令比INC reg和DEC reg更快。在过去,它更快,因为指令更小,我们没有缓存(或非常少)。今天,两种指令可能大致相同。

From a comment below, a reason for the "slowness" was the FLAGS register:

从下面的评论来看,“缓慢”的原因是FLAGS注册:

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

英特尔优化参考,第3.5.1.1节使用INC和DEC指令

From another, more current comment, it looks like the slowness referenced in that Intel document has been fixed in newer processors. So the use or non-use of these instructions should depend on the target processor if known in advance.

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


As pointed out by phresnel in a comment, the difference between i++ and ++i was probably not clear for many people. For an integer, the optimization is really trivial and will most certainly happen even with -O0. However, in C++, that's a different story. There is a class with both increment operators clearly showing that a copy is required for i++ (even if data_ is just an integer, although in that case you could also do: return data_++ -- it still requires a well hidden copy!):

正如phresnel在评论中指出的那样,对于很多人来说,i ++和++ i之间的差异可能并不明显。对于整数,优化实际上是微不足道的,即使使用-O0也肯定会发生。但是,在C ++中,这是一个不同的故事。有一个类都有两个增量运算符,清楚地表明i ++需要一个副本(即使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_;
};

Note that modern C++ compilers do not make two copies in the i++ function as the returned value can be optimized out without the need of an extra copy.

请注意,现代C ++编译器不会在i ++函数中生成两个副本,因为可以优化返回值,而无需额外的副本。

The difference between both cases can be shown as clearly slower if using i++ as described in Is there a performance difference between i++ and ++i in C++? (link mentioned by phresnel)

如果使用i ++,如果在C ++中i ++和++ i之间存在性能差异,那么两种情况之间的差异可以显示得明显更慢? (菲涅耳提到的链接)

#2


5  

There is no official document. The c spec does not declare that i++ must be faster than i+1 so compilers/optimizers are free to do what they like (and they can make different choices based on surrounding code and optimization level).

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

I use i++ because it's faster for me to read, with fewer characters to mistype.

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

#3


3  

Runthe code profiler between both of them it will be same for both i++ and i = i+1 for current version of gcc compiler. This purely depends on the compiler optimizations.

在两者之间使用代码分析器,对于当前版本的gcc编译器,i ++和i = i + 1都是相同的。这完全取决于编译器优化。

If you speak about processor specifically you can see the below chart for machine cycles,

如果您具体谈论处理器,您可以看到下面的机器周期图表,

INC - Increment

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 - Arithmetic Addition

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

You can find the machine cycles taken for each instruction ADD and INC for various processors, 8086, 80286, 80386, 80486,above, you can find this documented in intel processor manuals. Lower the machine cycles faster the response.

您可以找到针对各种处理器ADD和INC的机器周期,8086,80286,80386,80486,以上,您可以在英特尔处理器手册中找到这些内容。降低机器周期的响应速度。

#4


-1  

rmv=10;

rmv=rmv++;//rmv+1 both are same

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

printf("1.time=%d",rmv);

//output is 10 than second time increment 10+1 so,value is11

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

printf("2.time=%d",rmv++);//value is 11

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