深入理解 printf 函数中的参数处理顺序
在阅读文章前,请先思考下面的代码执行结果是什么:
1 |
|
如果你的答案为 3, 1
,那你就大错特错了。
实际上,这道题的答案为 2, 1
,那么这是为什么呢?
printf函数在处理参数的时候是从右向左处理的,其参数从右向左依次压入栈中,存放在栈中从高到低的地址里面,然后再格式化输出,输出时从低地址到高地址输出。即整个操作可以看做两部分:数据的处理(压栈)和格式化的输出(出栈)。
因此函数会先处理 (++p)->x
,因此第二个 %d
对应着 1
。然后再处理 ++p->x
,根据运算符优先级( ->
优先于 ++
,因此 ++p->x
相当于 ++(p->x)
)知第一个 %d
对应着 2
。
后来我发现事情又没有那么简单,请看下面的代码:
1 |
|
按照我们上述理论,总是从右向左解析,那么预期输出应为:
1 |
|
然而事实上这段代码跑下来实际结果为:
1 |
|
压栈顺序仍然是从右向左的,只是在底层
i++
和++i
的实现原理不一样。对于i++
的结果,是由ebp寻址函数栈空间来记录中间结果的,在最后给printf压栈的时候,再从栈中把中间结果取出来。而对于++i
的结果,则直接压寄存器变量,寄存器经过了所有的自增操作。 —— Go to Dessembly
这段代码的实际处理操作为:
- 压
i
的地址入栈; i=i+1
,压i
的地址入栈;- 压
i
的值入栈,i=i+1
; - 压
i
的地址入栈; - 出栈,为
i
的地址,解析为3
; - 出栈,为
2
; - 出栈,为
i
的地址,解析为3
; - 出栈,为
i
的地址,解析为3
。
因此结果为 3 2 3 3
。
参考文献
张春玲.可变参数函数printf调用过程的分析[J].电子制作,2014,000(002):058-058
注:文中所指的printf函数位于C语言标准库stdio.h中。结果均使用MinGW编译器验证,不同编译器结果可能不同。
深入理解 printf 函数中的参数处理顺序