最近在优化公司代码的时候,发现了一些for循环,条件变量的自增都使用的是 i ++ , 让我想起来之前想到的问题 —— i ++ 和 ++ i 。
很多书籍,都会写到i++和++i的问题,在大部分计算机人(包括本王)都熟悉的谭浩强版的教材中,也着重讲了 ++ 和 -- 操作,也加入了一些难点,这使得一部分人对这个操作上有了一些不一样的认识。
很经典的论述:
example 1 :
int k , i = 1; k = i++; </span>
example 2 :
int k , i = 1; k = ++i;</span>
ex1 呢,k的值是2,这时候 i 的值是1;ex2 呢,k的值是2,i 的值也是 2。这个结论是没有问题的,因为 ++i 是先运算 i = i + 1 ,所以在给 k 赋值前, i 的值就已经是 2 了。
在现在的编译器中,对 i ++ 和 ++ i 的优化已经将二者的性能都优化成一样的了,但是还是会存在性能上的不同。
java
package testJava; public class Test { public static void main(String args[]) { long start = System.currentTimeMillis(); for(long i = 0; i < 10000000; i++) { } long end = System.currentTimeMillis(); System.out.println((double)(end - start)); long new_start = System.currentTimeMillis(); for(long j = 0; j < 10000000; ++ j) { } long new_end = System.currentTimeMillis(); System.out.println((double)(new_end - new_start)); } }
<?php $start = microtime(true); for($i = 0; $i < 10000000; $i ++) { } $end = microtime(true); echo $end - $start, "\n"; echo "================================="; echo "\n"; $new_start = microtime(true); for($j = 0; $j < 10000000; ++ $j) { } $new_end = microtime(true); echo $new_end - $new_start, "\n";
c++
#include <iostream> #include <ctime> using namespace std; int main() { long count=10000000; clock_t start, finish, new_start, new_finish; start = clock(); for(int i=0; i < count; i ++) {} finish = clock(); cout<<(double)(finish-start)*1000/CLOCKS_PER_SEC<<endl; new_start = clock(); for(int j = 0; j < count; ++ j) {} new_finish = clock(); cout<<(double)(new_finish - new_start)*1000/CLOCKS_PER_SEC<<endl; return 0; }
<span style="white-space:pre"> </span>long start = [[NSDate date] timeIntervalSince1970]*1000; for (long i = 0; i < 10000000; i++) { } long end = [[NSDate date] timeIntervalSince1970]*1000; NSLog(@"%ld", end - start); long new_start = [[NSDate date] timeIntervalSince1970]*1000; for (long i = 0; i < 10000000; ++i) { } long new_end = [[NSDate date] timeIntervalSince1970]*1000; NSLog(@"%ld", new_end - new_start);</span>
最后执行结果呢,
java :
11
6
php :
0.2957980632782
=================================
0.25215196609497
C++ :
26.098
25.724
object-c :
[14770:3825658] 103
[14770:3825658] 54
在实际运行的时候,还是会有差异的,虽然差异不大。对上面的代码执行进行深入的调试剖析:
java 代码用javap -c test 运行虚拟机指令之后,得到如下:
3: lstore_1
4: lconst_0
5: lstore_3
6: lload_3
7: ldc2_w #3 // long 10000000l
10: lcmp
11: ifge 21
14: lload_3
15: lconst_1
16: ladd
17: lstore_3
18: goto 6
37: lstore 5
39: lconst_0
40: lstore 7
42: lload 7
44: ldc2_w #3 // long 10000000l
47: lcmp
48: ifge 60
51: lload 7
53: lconst_1
54: ladd
55: lstore 7
57: goto 42
C++ 代码用反汇编,得到如下结果:
mov eax,dword ptr [ebp-4]
mov ecx,eax
add eax,1
mov dword ptr [ebp-4],eax
mov ecx,dword ptr [ebp-4]
add ecx,1
mov dword ptr [ebp-4],ecx
在这里,看到了,在执行i++操作的时候,会将原 i 的值赋值给一个寄存器,而返回的就是寄存器里的值。用函数来表示的话,就是:
func i ++ :
temp = i;
i = i + 1;
return temp;
func ++ i :
i = i + 1;
return i;
当然,目前只是说明了 i++ 和 ++i 的一些差异,具体在生产环境中,还是要因情况而定,我是建议大家,在php和java的生产环境中,使用++i 来代替 i++ 。