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

news/2024/7/23 11:48:18 标签: 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;
}

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

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


http://www.niftyadmin.cn/n/104759.html

相关文章

【Redis 应用】 延时队列

一、应用场景&#xff1a; 对于只有一组消费者的消息队列&#xff0c;使用 Redis 。从而避免了 Kafka 、RabbitMQ 等专业消息队列在只有一组消费者时&#xff0c;还进行的繁琐的绑定过程。 注意&#xff1a; Redis 的消息队列不是专业的消息队列&#xff0c;它没有非常多的高…

Spark学习:spark相似算子解析

spark算子 一、Map、Flatmap和MapPartition二、repartition和coalesce三、reduceByKey和groupByKey四、collect、take和first一、Map、Flatmap和MapPartition 算子作用map接收一个高阶函数f,对每个算子进行f操作flatmap接收一个高阶函数f,对每个元素进行f操作,形成一个大的集合…

解决AAC音频编码时间戳的计算问题

1.主题音频是流式数据&#xff0c;并不像视频一样有P帧和B帧的概念。就像砌墙一样&#xff0c;咔咔往上摞就行了。一般来说&#xff0c;AAC编码中生成文件这一步&#xff0c;如果使用的是OutputStream流写入文件的话&#xff0c;就完全不需要计算时间。但在音视频同步或者使用A…

常用逻辑运算符

逻辑符号表格 逻辑符号含义描述&按位与将数字转成二进制计算&#xff0c;两个位都为1时&#xff0c;结果才为1|或两个位都为0时&#xff0c;结果才为0 &#xff0c;反知任何一个为1结果为1^异或两个位相同为0&#xff0c;不同为1<<左移整体二进位全部左移若干位&…

基于SpringCloud的可靠消息最终一致性06:轮询事务消息

上一节把可靠消息最终一致性的正常逻辑代码顺序执行了一次,并且对于同一个事务消息,在正常情况下它要被发送至少两次。 这是因为在发送消息之前,TransactionMessageService就已经把消息保存到了数据库中。而在首次消费完消息后,TransactionMessageListener并没有从数据库中…

jmeter基本使用

jmeter基本使用 1.jemeter基本介绍 Jmeter 是什么 Apache JMeter 是 Apache 组织基于 Java 开发的压力测试工具&#xff0c;用于对软件做压力测 试JMeter 可用于 Web 应用测试&#xff0c;后来扩展到了其他测试领域具体来说, Jmeter 可以测试静态和动态资源&#xff0c;比如…

Codeforces Round #851 (Div. 2) C. Matching Numbers

传送门 题意&#xff1a; 给你一个n&#xff0c;问你在1-2n中&#xff0c;能不能组成一个由n个元素组成的数组&#xff08;每个元素由1-2n中的任意两个数之和&#xff09;s&#xff0c;问你存不存在s&#xff0c;使并且后一个元素比前一个元素大1。如果存在就输出这个数组 思路…

动态规划——糖果

由于在维护世界和平的事务中做出巨大贡献&#xff0c;Dzx被赠予糖果公司2010年5月23日当天无限量糖果免费优惠券。在这一天&#xff0c;Dzx可以从糖果公司的 N 件产品中任意选择若干件带回家享用。糖果公司的 N 件产品每件都包含数量不同的糖果。Dzx希望他选择的产品包含的糖果…