关于i++和++i

简介: 最近在优化公司代码的时候,发现了一些for循环,条件变量的自增都使用的是 i ++ , 让我想起来之前想到的问题 —— i ++  和 ++ i 。 很多书籍,都会写到i++和++i的问题,在大部分计算机人(包括本王)都熟悉的谭浩强版的教材中,也着重讲了 ++ 和 -- 操作,也加入了一些难点,这使得一部分人对这个操作上有了一些不一样的认识。 很经典的论述: example 1 :

最近在优化公司代码的时候,发现了一些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

<?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;
}


object-c 

<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++ 。


相关文章
|
C++ Windows
Visual Studio 2019 实现并行编译
使用 Visual Studio 2019 实现并行编译
386 0
Visual Studio 2019 实现并行编译
Beyond Compare 4密钥过期解决办法,超实用
Beyond Compare 4密钥过期解决办法,超实用
23048 1
|
3月前
|
安全 C++
超级好用的C++实用库之环形内存池
超级好用的C++实用库之环形内存池
64 5
|
3月前
|
存储 数据处理 C++
超级好用的C++实用库之点阵字体
超级好用的C++实用库之点阵字体
86 0
|
缓存 网络协议 Windows
一分钟解决Github连接慢或者无法连接,亲测有效!
一分钟解决Github连接慢或者无法连接,亲测有效!
4699 0
一分钟解决Github连接慢或者无法连接,亲测有效!
|
Unix Linux API
开源库介绍:libusb 及其使用
开源库介绍:libusb 及其使用
4239 0
开源库介绍:libusb 及其使用
|
前端开发 算法 安全
【C++知识点】C++20 常用新特性总结
【C++知识点】C++20 常用新特性总结
2585 0
|
IDE Linux 开发工具
Qt Creator的IDE选项配置参数的保存路径在哪里?即QtProject文件夹在哪里?(Windows/Linux/MacOS)
Qt Creator的IDE选项配置参数的保存路径在哪里?即QtProject文件夹在哪里?(Windows/Linux/MacOS)
1291 0