您的位置:首页 > 其它

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

2017-10-23 11:55 267 查看
先来看一个例子:

#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()函数的处理过程,我们可以看到,是先将参数从右到左遍历一遍,最后才执行打印操作,而不是遍历一个打印一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  printf c
相关文章推荐