标题:C++里i++与++i的效率与区别


i++++i是一种特殊的自增运算,类似的还有自减操作运算i----i。下面从CC++两个角度来比较这两种形式的运算方式。

1C中:

简单的来说,++ii++,在作为一个语句单独使用时(如i++;或者++i;),就是 i = i + 1,它们之间没有区别。 而在做为语句的一部分时,a = ++i,相当于 i=i+1; a = i;通过表达式就可以看出,因为++在前,所以是先执行加1操作,再执行赋值操作。而 a = i++,相当于 a = i; i=i+1;++在后,所以是先执行赋值操作,再执行加1操作。

问题:试分析下面的代码在X86/Linux上的输出结果。

代码1

 

void main()

{

     long i;

 

     i = 0;

     printf("%ld\n", (++i)+(++i)+(++i));

}

 

输出为:7

代码2

 

void main()

{

     long i;

 

     i = 0;

     printf("%ld\n", (++i)+((++i)+(++i)));

}

 

输出为:9

分析:对于++i来说,实质就是i = i + 1。这个结果应该是保存在寄存器中。那么无论计算顺序为何,都不会影响到最后的计算结果。即代码1的结果应该为6,代码2的结果也应该为6。但是实际的结果为什么为79呢?是不是因为寄存器不够而没有放进寄存器中呢?现代计算机,有足够多的寄存器来存放++i的中间结果。唯一的可能就是编译程序就根本没有打算把++i的中间结果放进寄存器中。

实际上,在X86/Linux平台上,专门有一条指令用于++i操作,那就是INC指令。INC指令直接对i进行加1操作,并将结果保存在i中,而不是寄存器中。现在来分析代码1对应的汇编代码片段:

...

pushl %ebp             //ebp入栈

movl %esp, %ebp        //栈顶指针存入ebp寄存器

subl $4 %esp           //在栈上为局部变量i分配空间

movl $0, 4(%ebp)       //4(%ebp)=i,将i赋初值0

incl -4(%ebp)          //++i,将i1,此时i1

incl -4(%ebp)          //++i,将i1,此时i2

movl -4(%ebp), %eax    //i放入eax,值为2

movl -4(%ebp), %edx    //i放入edx,值为2

addl %edx, %eax        //(++i) + (++i),将ii相加,eax值为4

incl -4(%ebp)          //++i,将i1,此时i3

addl -4(%ebp), %eax    //((++i) + (++i)) + (++i),即3+4=7

...

代码2的汇编代码片段:

...

pushl %ebp             //ebp入栈

movl %esp, %ebp        //栈顶指针存入ebp寄存器

subl $4 %esp           //i分配空间

movl $0, 4(%ebp)       //4(%ebp)=i,将i赋初值0

incl -4(%ebp)          //++i,此时i1

incl -4(%ebp)          //++i,此时i2

incl -4(%ebp)          //++i,此时i3

movl -4(%ebp), %eax    //i值放入eax

movl -4(%ebp), %edx    //i值放入edx

addl %edx, %eax        //edxeax相加,即((++i)+(++i)),此时eax值为6

movl %eax, %edx        //eax放入edx

addl -4(%ebp), %edx    //edxi相加,即(++i)+((++i)+(++i))),即6+3=9

...

相反,在SPARC/Solaris系统上,由于不存在INC指令,那么计算的结果将保存在寄存器中,因此,运算结果为6

2C++中:

C++中,简单类型的i++++iC相同。不同的是,由于在C++中可以重载运算符,在实现新的类型对象时重载i++++i操作时的区别。比如:

 

class A

{

public:

     ...

     A & operator++();           //++ i

     const A operator++(int);         //i++

     ...

};

A&  A::operator++()

{

     *this += 1;   //先加1

     return *this; //返回加1后的值

}

const A  A::operator++(int)

{

     A oldValue = *this;         //保存旧值

     ++(*this);             //再加1

     return oldValue;

}

 

从上面的++ii++的实现看出,在C++中,对与非内建型别来说,前自增运算(++i)返回的是对象的引用,而后自增运算返回的是对象,返回对象将造成拷贝构造函数更多的调用,所以++i的效率要高与i++

 

但是,对于内建型别(也就是int,short,char等类型),i++++i的效率几乎没有区别(因为内建型别没有拷贝构造函数)。与此类似的是i----i



看文字不过瘾?点击我,进入周哥教IT视频教学
麦洛科菲长期致力于IT安全技术的推广与普及,我们更专业!我们的学员已经广泛就职于BAT360等各大IT互联网公司。详情请参考我们的 业界反馈 《周哥教IT.C语言深学活用》视频

我们的微信公众号,敬请关注