Difference between i++ and ++i in a loop?
++被称为后缀。
将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 |
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; } |
现在,把
既然你问循环中的差异,我想你是说
1 2 | for(int i=0; i<10; i++) ...; |
在这种情况下,在大多数语言中都没有区别:无论您是否编写
上面不重要的原因是你没有使用EDOCX1的值(0)。另一件事是当你这样做的时候
1 2 | for(int i=0, a = 0; i<10; a = 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. |
在这两种情况下,没有实际的差异,
但是在表达式中使用它时有一个区别,例如:
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循环没有区别。
但是在
1 2 3 | while(i++ < 10) { ... } //compare then increment while(++i < 10) { ... } //increment then compare |
是的,在
因为代码中的
++i 是指i 的增量值乘以1,然后再对i 进行评价。i++ 是指将i 及以后的i 增值1。
所以,从每两个表达式中得到的结果是不同的,因为每个表达式中计算的结果是不同的。
例如;
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) } |
它们都会增加数字。
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构造)。
对于用户定义类型的
另外,在
我不知道其他语言,但在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 |