for循环中的++i和i++有区别吗?这仅仅是语法问题吗?


当前回答

下面是一个Java-Sample和字节码,后增量和前增量显示字节码没有区别:

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 PreOrPostIncrement):

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

}

其他回答

Pre-increment ++i增加i的值,并计算为新的增量值。

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

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

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

在c++中,如果可以使用前递增,则通常是首选。

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

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

这主要只在被递增的变量是用户定义的具有重写++操作符的类型时才会出现问题。对于基本类型(int等),没有性能差异。但是,作为指导原则,坚持使用前增量操作符是值得的,除非确实需要后增量操作符。

这里还有一些讨论。

In C++ if you're using STL, then you may be using for loops with iterators. These mainly have overridden ++ operators, so sticking to pre-increment is a good idea. Compilers get smarter all the time though, and newer ones may be able to perform optimizations that mean there's no performance difference - especially if the type being incremented is defined inline in header file (as STL implementations often are) so that the compiler can see how the method is implemented and can then know what optimizations are safe to perform. Even so, it's probably still worth sticking to pre-increment because loops get executed lots of times and this means a small performance penalty could soon get amplified.


在其他语言(如c#)中,c++操作符不能重载,在性能上没有区别。在循环中用于使循环变量前进,前增量操作符和后增量操作符是等效的。

更正:在c#中重载c++是允许的。不过,与c++相比,在c#中,你不能独立地重载前版本和后版本。因此,我假设在c#中调用++的结果没有被赋值给变量或用作复杂表达式的一部分,那么编译器会将++的前后版本简化为执行等效的代码。

要理解FOR循环的作用

上图显示FOR可以转换为WHILE,因为它们最终具有完全相同的汇编代码(至少在gcc中)。所以我们可以把FOR分解成几部分,来理解它的功能。

for (i = 0; i < 5; ++i) {
  DoSomethingA();
  DoSomethingB();
}

等于WHILE版本

i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
  DoSomethingA();
  DoSomethingB();
  ++i; //third argument (another statement) of for
}

It means that you can use FOR as a simple version of WHILE: The first argument of FOR (int i) is executed, outside, before the loop. The third argument of FOR (i++ or ++i) is executed, inside, in the last line of the loop. TL:DR: no matter whether i++ or ++i, we know that when they are standalone, they make no difference but +1 on themselves. In school, they usually teach the i++ way, but there are also lots of people prefer the ++i way due to several reasons. NOTE: In the past, i++ has very little impact on the performance, as it does not only plus one by itself, but also keeps the original value in the register. But for now, it makes no difference as the compiler makes the plus one part the same.

在这两种情况下,'i'将加1。

但是当你在表达式中使用它时,就有区别了,例如:

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

下面是一个Java-Sample和字节码,后增量和前增量显示字节码没有区别:

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 PreOrPostIncrement):

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

}

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

        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次,但第二个不是。

这通常用于简单的while(x——> 0);- -循环迭代数组中的所有元素(这里不包括foreach-construct)。