关于post增量:循环中i ++和++ i之间的差异?

Difference between i++ and ++i in a loop?

++ii++for循环中有区别吗?它只是一个语法问题吗?


++被称为后缀。

将1添加到,返回旧值。

++A称为前缀。

将1添加到,返回新值。

C:

1
2
3
4
5
6
7
8
9
10
11
12
13
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
    Console.WriteLine(++i);
}
Console.WriteLine("");

i = 0;
foreach (string item in items)
{
    Console.WriteLine(i++);
}

输出:

1
2
3
4
5
6
7
8
9
1
2
3
4

0
1
2
3

foreachwhile循环取决于您使用的增量类型。对于下面这样的for循环,它没有任何区别,因为您没有使用i的返回值:

1
2
3
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }

0 1 2 3 4
0 1 2 3 4

如果使用评估值,则增量类型将变得重要:

1
2
int n = 0;
for (int i = 0; n < 5; n = i++) { }


pre increment++i使i的值递增,并计算为新的递增值。

1
2
3
4
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );

增量后i++增加i的值,并计算为原始的非增量值。

1
2
3
4
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );

在C++中,预增量通常是首选的,在这里您也可以使用。

这是因为如果使用后增量,则可能需要编译器生成创建额外临时变量的代码。这是因为要递增的变量的前一个值和新值都需要保存在某个位置,因为它们可能需要保存在要计算的表达式的其他位置。

因此,至少在C++中,可以有一个性能差异来指导您选择使用哪个。

这主要是当要递增的变量是一个用户定义的类型,并且带有一个重写的++运算符时出现的问题。对于基本类型(int等),没有性能差异。但是,值得坚持使用预增量操作符作为指导,除非后增量操作符确实是必需的。

这里还有一些讨论:https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/c-1040/increment-operators.htm

在C++中,如果你使用STL,那么你可能会使用带有迭代器的循环。这些主要重写了++运算符,因此坚持使用预增量是一个好主意。不过,编译器总是变得更聪明,而较新的编译器可能能够执行优化,这意味着没有性能差异——特别是如果正在递增的类型是在头文件中以内联方式定义的(通常是STL实现),这样编译器就可以看到该方法是如何实现的,然后可以知道什么是优化配置。执行安全。即使如此,仍然值得坚持预增量,因为循环执行了很多次,这意味着一个小的性能损失很快就会被放大。

在其他语言中,如C中不能重载++运算符,则没有性能差异。在循环中使用循环变量前进,前后增量运算符是等效的。

更正:允许在C中重载+。不过,与C++相比,C语言中不能独立加载前置和后置版本。因此,我假设如果在C中调用++的结果没有分配给一个变量或作为复杂表达式的一部分使用,那么编译器会将++的前后版本减少到执行相同的代码。


在C中,在for循环中使用时没有区别。

1
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }

输出的内容与

1
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }

正如其他人所指出的,当在一般情况下使用i++和++时,我有一个微妙但显著的区别:

1
2
3
4
int i = 0;
Console.WriteLine(i++);   // Prints 0
int j = 0;
Console.WriteLine(++j);   // Prints 1

i++读取i的值,然后将其递增。

++我增加值,然后读取它。


问题是:

Is there a difference in ++i and i++ in a for loop?

答案是:不。

为什么每一个答案都必须详细解释递增前和递增后的情况,而这甚至没有被问到?

for循环:

1
2
3
4
5
6
for (int i = 0; // Initialization
     i < 5;     // Condition
     i++)       // Increment
{
   Output(i);
}

将转换为此代码而不使用循环:

1
2
3
4
5
6
7
8
9
10
11
int i = 0; // Initialization

loopStart:
if (i < 5) // Condition
{
   Output(i);

   i++ or ++i; // Increment

   goto loopStart;
}

现在,把i++++i作为增量放在这里有关系吗?不,它不是因为增量操作的返回值无关紧要。执行完for循环体中的代码后,i将递增。


既然你问循环中的差异,我想你是说

1
2
for(int i=0; i<10; i++)
    ...;

在这种情况下,在大多数语言中都没有区别:无论您是否编写i++++i,循环的行为都是相同的。在C++中,您可以编写自己的版本的++运算符,并且如果EDCOX1(2)是用户定义的类型(例如,您自己的类),则可以为它们定义单独的含义。

上面不重要的原因是你没有使用EDOCX1的值(0)。另一件事是当你这样做的时候

1
2
for(int i=0, a = 0; i<10; a = i++)
    ...;

现在,有一个区别,因为正如其他人指出的,i++表示增量,但计算到以前的值,而++i表示增量,而计算到i时(因此它将计算到新的值)。在上述情况下,a被赋予i的前一个值,而i是递增的。


正如这段代码所示(参见注释中的分解的MSIL),C 3编译器在for循环中对i++和++i没有区别。如果采用的是i++或++i的值,肯定会有区别(这是在Visual Studio 2008/Release Build中编译的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreOrPostIncrement
{
    class Program
    {
        static int SomethingToIncrement;

        static void Main(string[] args)
        {
            PreIncrement(1000);
            PostIncrement(1000);
            Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
        }

        static void PreIncrement(int count)
        {
            /*
            .method private hidebysig static void  PreIncrement(int32 count) cil managed
            {
              // Code size       25 (0x19)
              .maxstack  2
              .locals init ([0] int32 i)
              IL_0000:  ldc.i4.0
              IL_0001:  stloc.0
              IL_0002:  br.s       IL_0014
              IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0009:  ldc.i4.1
              IL_000a:  add
              IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0010:  ldloc.0
              IL_0011:  ldc.i4.1
              IL_0012:  add
              IL_0013:  stloc.0
              IL_0014:  ldloc.0
              IL_0015:  ldarg.0
              IL_0016:  blt.s      IL_0004
              IL_0018:  ret
            } // end of method Program::PreIncrement            
             */
            for (int i = 0; i < count; ++i)
            {
                ++SomethingToIncrement;
            }
        }

        static void PostIncrement(int count)
        {
            /*
                .method private hidebysig static void  PostIncrement(int32 count) cil managed
                {
                  // Code size       25 (0x19)
                  .maxstack  2
                  .locals init ([0] int32 i)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  IL_0002:  br.s       IL_0014
                  IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0009:  ldc.i4.1
                  IL_000a:  add
                  IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0010:  ldloc.0
                  IL_0011:  ldc.i4.1
                  IL_0012:  add
                  IL_0013:  stloc.0
                  IL_0014:  ldloc.0
                  IL_0015:  ldarg.0
                  IL_0016:  blt.s      IL_0004
                  IL_0018:  ret
                } // end of method Program::PostIncrement
             */
            for (int i = 0; i < count; i++)
            {
                SomethingToIncrement++;
            }
        }
    }
}

一个(++i)是预增量,一个(i++)是后增量。不同之处在于表达式立即返回的值。

1
2
3
4
5
6
7
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1

编辑:汪汪,完全忽略了事情的循环方面。当for(…;…;)是"step"部分时,for循环没有实际的区别,但它可以在其他情况下发挥作用。


这里有一个Java示例,字节码、后加和预增量在Bytecode中没有差别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PreOrPostIncrement {

    static int somethingToIncrement = 0;

    public static void main(String[] args) {
        final int rounds = 1000;
        postIncrement(rounds);
        preIncrement(rounds);
    }

    private static void postIncrement(final int rounds) {
        for (int i = 0; i < rounds; i++) {
            somethingToIncrement++;
        }
    }

    private static void preIncrement(final int rounds) {
        for (int i = 0; i < rounds; ++i) {
            ++somethingToIncrement;
        }
    }
}

现在,对于字节代码(javap-private-c preproposoticrement):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;

static {};
Code:
0:  iconst_0
1:  putstatic   #10; //Field somethingToIncrement:I
4:  return

public PreOrPostIncrement();
Code:
0:  aload_0
1:  invokespecial   #15; //Method java/lang/Object."<init>":()V
4:  return

public static void main(java.lang.String[]);
Code:
0:  sipush  1000
3:  istore_1
4:  sipush  1000
7:  invokestatic    #21; //Method postIncrement:(I)V
10: sipush  1000
13: invokestatic    #25; //Method preIncrement:(I)V
16: return

private static void postIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

private static void preIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

}

如果在循环中不使用递增后的值,则没有区别。

1
2
3
4
5
6
for (int i = 0; i < 4; ++i){
cout<<i;      
}
for (int i = 0; i < 4; i++){
cout<<i;      
}

两个循环都将打印0123。

但当您在循环中使用递增/递减后的值时,会出现以下差异:

预增量循环:

1
2
3
4
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<"";      
cout<<k<<"";
}

输出:0 01 12 23 3

后增量循环:

1
2
3
4
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<"";      
cout<<k<<"";
}

输出:0 01 02 13 2

我希望通过比较产量可以清楚地看出差异。这里要注意的是,增量/减量总是在for循环的末尾执行,因此可以解释结果。


是的,有。差异在返回值中。"++i"的返回值为递增i后的值,"+"的返回值为递增前的值。这意味着代码如下所示:

1
2
3
int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.

因此,a为2,b和c分别为1。

我可以这样重写代码:

1
2
3
4
5
6
7
8
9
int a = 0;

// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.

// a++;
c = a; // setting first.
a = a + 1; // incrementing second.

在这两种情况下,没有实际的差异,i将增加1。

但是在表达式中使用它时有一个区别,例如:

1
2
3
4
5
6
7
int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3

与循环和性能差异相比,++i和i++有更多的差别。++我返回一个l值,而i++返回一个r值。基于此,您可以对(++i)做很多事情,但不能对(i++)做很多事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:

T& operator ++ ( )
{
   // logical increment
   return *this;
}

const T operator ++ ( int )
{
    T temp( *this );
    ++*this;
    return temp;
}

在javascript中,由于以下原因,i++可能更好地使用:

1
2
3
4
var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.

当数组(我认为全部)和其他一些函数和调用使用0作为起点时,您必须将i设置为-1,以便在使用++i时使循环与数组一起工作。

使用i++时,以下值将使用增加的值。你可以说i++是人类的计数方式,因为你可以从0开始。


这让我很困惑,为什么人们会把for循环中的增量表达式写成i++。

在for循环中,当第三个组件是简单的increment语句时,如

1
for (i=0; i<x; i++)

1
for (i=0; i<x; ++i)

结果执行没有区别。


正如@jon b所说,for循环没有区别。

但是在whiledo...while循环中,如果与++ii++进行比较,你会发现一些不同之处。

1
2
3
while(i++ < 10) { ... } //compare then increment

while(++i < 10) { ... } //increment then compare


是的,在for循环中,++ii++之间存在差异,但在不常见的使用情况下;当在for块、循环测试表达式或循环变量之一中使用带递增/递减运算符的循环变量时。不,这不仅仅是语法问题。

因为代码中的i表示对表达式i进行计算,而运算符不表示计算,而只是一个操作;

  • ++i是指i的增量值乘以1,然后再对i进行评价。
  • i++是指将i及以后的i增值1。

所以,从每两个表达式中得到的结果是不同的,因为每个表达式中计算的结果是不同的。--ii--的情况相同。

例如;

1
2
3
4
5
6
7
8
9
10
let i = 0

i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2

在不常见的用例中,尽管下一个示例听起来有用或不重要,但它显示了一个区别

1
2
3
4
5
6
7
for(i=0, j=i; i<10; j=++i){
    console.log(j, i)
}

for(i=0, j=i; i<10; j=i++){
    console.log(j, i)
}


它们都会增加数字。++i相当于i = i + 1

i++++i非常相似,但并不完全相同。两者都增加了数值,但++i在计算当前表达式之前增加了数值,而i++在计算表达式之后增加了数值。

1
2
3
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =

检查这个链接。


循环可能有所不同。这是后/前增量的实际应用。

1
2
3
4
5
6
7
8
9
10
11
        int i = 0;
        while(i++ <= 10) {
            Console.Write(i);
        }
        Console.Write(System.Environment.NewLine);

        i = 0;
        while(++i <= 10) {
            Console.Write(i);
        }
        Console.ReadLine();

第一个数为11,循环11次,第二个数不为11。

大多数情况下,这相当于在简单的while(x-->0);--循环中迭代,例如数组的所有元素(此处不包括foreach构造)。


对于用户定义类型的i而言,这些运算符可以(但不应该)在循环索引上下文中具有显著不同的语义,这可能(但不应该)影响所描述循环的行为。

另外,在c++中,使用预增量形式(++i通常最安全,因为它更容易优化。(斯科特·兰厄姆打败了我。诅咒你,斯科特)


我不知道其他语言,但在Java++中,i是一个前缀增量,意思是:i增加1,然后在i驻留的表达式中使用i的新值,i++是一个后缀增量,这意味着:使用表达式中的i的当前值,然后将其增加1。例子:

1
2
3
4
5
6
7
public static void main(String [] args){

    int a = 3;
    int b = 5;
    System.out.println(++a);
    System.out.println(b++);
    System.out.println(b);

}输出为:


I++;++I;两者都与表达式中未使用的相似。

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {

     public static void main (String []args) {

     int j = 0 ;
     int k = 0 ;
     ++j;
     k++;
    System.out.println(k+""+j);

}}

prints out :  1 1