printf函数参数出栈入栈问题
1.问题
下面是一个简单的printf打印的程序,让我们观察一下程序的输出结果:
- 系统环境为ubuntu, 编译环境为GCC
- 看一下结果和我们预想的是否有很大的区别,那么想一下,为什么会出现这样的结果?接下来,让我们一起分析一下。
2.分析原理
-
编译器在处理printf的参数时,压栈顺序为从左到右,也就是说从左到右的计算,但是(“计算"不等于"输出”)
-
好了,有了理论支持我们来分析一下本文开头所抛出的问题: a++和++a的压栈区别:在计算是时,遇到a++会记录此时a的值作为最后输出的结果,出栈后再对a的值进行加1。遇到++a时则不会将此时的计算结果作为最终的结果的输出,会先修改a的值,然后再将a入栈,所以在在最终的时候都输出a的值(所以++a和a的结果总是一样的)。
-
简单来说,++a打印时会优先将a的值加1然后入栈,此时a的值已经改变了,所以出栈的时候a和++a打印的结果是一样的。
-
经过上面的分析,我们肯定还不死心的,事实胜于雄辩,那么让我们再加一条打印验证一下:
结果发现c和++c的打印结果是一样的,这就证明了前面的想法。
那么为什么会出现这样的结果呢?
-
让我们继续往底层分析,对于a++,是ebp寻址函数栈空间来记录结果的,在最后给printf压栈的时候,再从栈中把中间结果取出来,所以就导致a++和a的值不一样;而对于++a的结果,则直接压寄存器变量,寄存器经历了所有的自增操作(入栈成功时,a的值已经改变)。
-
出栈的时候,则是从右往左出栈的。
-
所以,a++在输出的时候并没有改变此时a的值,a的值的改变在下一个参数入栈时才会体现出来。a和++a则输出最终的a的值,而a++则输出上一次参数入栈改变前的值。
那么,现在我们就可以理解从原理上理解开头的程序的结果了。