以下代码测试于GCC环境,DEV C++和VS2022。
printf
函数参数的计算顺序
printf()
函数输出时,表达式的计算顺序是从右到左的。
一般使用printf()
函数时不会注意到这个问题,但是当输出的多个表达式是一个变量的话,如果不注意它们的计算顺序就会出现与预料中不一样的结果。
比如:
#include<stdio.h>
int main(){
int a = 10;
printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);
return 0;
}
按照正常来说,这段代码的输出结果应该为:
10 12 11 11 10
但使用编译器运行过后,输出的正确结果应该是:
9 10 10 10 10
为什么和预料的完全不一样?因为printf()
函数里表达式的计算顺序是从右往左的。
也就是说,a++, ++a, --a, a--, a
这五个表达式,是先从右边开始算,也就是a
是第一个,a--
是第二个。
其实printf()
函数处理参数时是一个压栈的过程。它先会将printf()
内的表达式参数从右往左的进行压栈,同时对它们完成计算。计算过程分析如下:
printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);
因为所有表达式操作的都是变量a,所以栈里面其实都放的a。
| 9 | 此时的表达式为:a++。a当前值为9,栈里当前的值就为9,而后a的值变为10。
|_______|
| 9 | 此时的表达式为:++a。a当前值为8,栈里当前的值就为9,a的值为9。
|_______|
| 8 | 此时的表达式为:--a。a当前值为9,栈里当前的值就为8,a的值为8。
|_______|
| 10 | 此时的表达式为:a--。a当前值为10,栈里当前的值就为10,而后a的值变为9。
|_______|
| 10 | 此时的表达式为:a。 a当前值为10,栈里当前的值就为10。
|_______|
计算时的栈
那这样算出来的结果就是:
9 9 8 10 10
可为什么还是和正确答案不一样?因为这五个表达式操作的是同一个变量。也就是说,输出的其实应该都是a
变量,因为加来减去的都是a
本身,所以输出结果应该是最后一次a
的值,也就是从右往左计算完后的a
的值。
那么结果就应该是:
10 10 10 10 10
发现还是和正确答案不一样,这到底为什么?因为涉及到了后置的自增自减的操作。
在这五个表达式中,有后置的自加自减操作,而后置的自加自减操作,是先取自身值参与运算后才对自身值进行修改。
int a = 10;
int b = a++;
printf("b = %d\n", b); // b = 10
相当于:int b = a++; ==> int t = a; // 先取自身值
b = t; // 参与运算
a = a + 1; // 再对自身值进行修改
所以,printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);
在以上分析过程中,a++
和a--
先是用了一个临时变量t
将栈里的位置占着,这个t
是a
进行自操作前的值,然后再进行其他表达式的运算,这样其他表达式会对a
的值进行修改,但是不会影响t
的值,所以,输出的值也不会收到影响。
printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);
因为所有表达式操作的都是变量a,所以栈里面其实都放的a。
| t | 此时的表达式为:a++。a当前值为9,int t = a; a = a + 1; 栈里当前的值就为t,而后a的值变为10。
|_______|
| a | 此时的表达式为:++a。a当前值为8,栈里当前的值就为9,a的值为9。
|_______|
| a | 此时的表达式为:--a。a当前值为9,栈里当前的值就为8,a的值为8。
|_______|
| t | 此时的表达式为:a--。a当前值为10,int t = a; a = a - 1; 栈里当前的值就为t,而后a的值变为9。
|_______|
| a | 此时的表达式为:a。 a当前值为10,栈里当前的值就为10。
|_______|
计算时的栈
然后栈里所有的a
都变成最后一次计算后的a
的值,也就是10,所以最终结果为:
9 10 10 10 10
结论:printf()
函数中的表达式参数的计算顺序是从右往左的,当所有表达式计算完后,将最后的值赋给printf()
函数所有引用当前变量的位置,除了进行了后置自增/自减操作的位置。
函数参数计算顺序
通过测试,发现以上处理参数的方式可能并不是printf()
函数所独有的,而是所有函数都是这样。
#include<stdio.h>
void fun(int i, int j, int k){
printf("%d %d %d\n", i, j, k);
}
int main(){
int a = 10;
fun(a++, ++a, --a); // 10 11 11
a = 10;
fun(++a, a--, a++); // 11 11 10
return 0;
}
该段代码的所得的结果符合以上得出的结论。
以上所有结论都基于自测,没有理论依据,如有不当处,欢迎各位大佬指出。😄