zl程序教程

您现在的位置是:首页 >  其它

当前栏目

关于i++和++i

关于 ++
2023-09-14 09:02:06 时间
最近在优化公司代码的时候,发现了一些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

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



在开发大型系统过程中,往往会出现这样一种情况: 我有一部分基础数据,是类classA是从数据库A读取出来的,其他很多的功能都是基于这个基础数据来操作的。现在呢,我想把数据从数据库A变成从另外的数据源去获取,这时候,要修改起来就比较麻烦,要修改其他很多类的代码。这种设计显然是不够灵活的,换句话说,就是紧耦合的,系统中某个部分的函数或类严重依赖于系统的其他部分中的函数或类的行为和结构。
【OpenCV学习】一个多维数组(矩阵)和一个一维,但是包含高维数据的数组之间的区别 作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 我们需要了解一个多维数组(矩阵)和一个一维,但是包含高维数据的数组之间的区别。假设,你有n个点(每个点有x,y,z坐标值)需要保存到CvMat* 中,你其实有四种方式可以使用,但这四种方式的存储形式不同。
边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。
【Linux实用技术】LFS6.3构建实录 作者:gnuhpc  出处:http://www.cnblogs.com/gnuhpc/   几点说明: 1.  本文档参考了 金步国在LinuxSir 上的文档和对 LFS 英文文档的翻译 。