C语言——printf()计算参数顺序


以下代码测试于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将栈里的位置占着,这个ta进行自操作前的值,然后再进行其他表达式的运算,这样其他表达式会对a的值进行修改,但是不会影响t的值,所以,输出的值也不会收到影响。

printf("%d %d %d %d %d\n", a++, ++a, --a, a--, a);
因为所有表达式操作的都是变量a,所以栈里面其实都放的a。
        |	t	|	此时的表达式为:a++。a当前值为9int 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当前值为10int 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;
}

该段代码的所得的结果符合以上得出的结论。

以上所有结论都基于自测,没有理论依据,如有不当处,欢迎各位大佬指出。😄

  • 47
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多低调

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值