对i++,i--,++i,--i深刻认识以及printf()函数打印的过程

来源:互联网 发布:linux系统下载iso 编辑:程序博客网 时间:2024/06/06 01:33

先来看一个例子:

#inlcude <stdio.h>int main(){    int i = 0;    printf("%d,%d,%d\n", i++, --i, i++);}

有一部分人认为打印的结果应该是0,0,0.
下面是VS2013运行出来的结果:

这里写图片描述

大家心里肯定会有疑惑,为什么会是这样的结果?我们不妨先来分析一下。

大家都很清楚,printf()这个函数在打印参数内容时,是从右往左的,当有多个参数时(依次入栈的原因),printf()函数执行时是遍历一个参数打印一个参数呢?还是先遍历一遍参数然后在依次打印呢?大家有没有考虑过呢?

我们不妨假设printf()函数执行时遍历一个参数打印一个参数:
1、首先处理的是最右边的表达式i++,打印出其结果为0,而后i的值变为1;
2、接下来处理的是表达式–i,由于i的值已变为1,所以打印的结果为0,而后i的值变为0;
3、最后处理的是最左边的表达式i++,此时i值为0,所以打印的结果为0,而后i的值变为1。
通过上面的分析,可以看出打印的结果是0,0,0,可真的是这样吗?
我们先来看一下上述代码的汇编代码:

这里写图片描述

1、在红色框里,处理表达式i++时,先通过寄存器eax先将内存中i的值(为0)放入一个系统临时开辟的整型大小的地址空间(ptr [ebp-0D0h]开始的地址空间)中保存起来,之后通过寄存器ecx将内存中i的值加1再将加1后的结果放到i原来的内存中去,此时内存中i的值变为1;

这里写图片描述

2、红色框里的指令是用来处理表达式–i的,可以看出在处理表达式–i时,是直接通过寄存器edx将内存中i的值减1之后再将减1后的结果放到i原来的内存中去,此时i的值变为0.;

这里写图片描述

3、接下来处理最左边的表达式i++,可以看出红色框内的代码和处理最最右边的表达式i++的代码几乎一样,只是存放i值的地址不一样,这次是通过寄存器eax将i的值0存放到内存dword ptr [ebp-0D4h]开始的内存单元中。

接下来便是入栈了:

这里写图片描述

第一步是通过寄存器edx将内存ptr [ebp-0D0h]开始的连续四个地址空间的值入栈,该值为0;

第二步是将内存中i的值通过寄存器eax入栈,此时i的值为1;

第三步通过通过寄存器edx将内存ptr [ebp-0D4h]开始的连续四个地址空间的值入栈,该值为0。

之后系统将当前指令的下一条指令的地址入栈(现场保护),然后调用printf()函数依次打印上述表达式的结果,得到的结果是0,1,0

通过上面的分析,相信大家对i++,i–,++i,–i以及printf()函数打印的过程已经深刻理解了。

最后,总结一下:
对于前置++、–处理的时候系统会直接操作不产生临时量,只需三条代码;对于后置++、–处理的时候会先产生一个临时量,而后通过临时量返回结果,需要五条代码,所以在同样的环境下前置++或–要比后置++或–效率要高。
对于printf()函数的处理过程,我们可以看到,是先将参数从右到左遍历一遍,最后才执行打印操作,而不是遍历一个打印一个。

原创粉丝点击