printf()中a++与++a的输出问题
在C语言中有个很常用的函数printf(),使用时从右向左压栈,也就是说在printf("%d %d %d %d\n",a,a++,++a,++a)
中,依次从右向左开始计算,计算完后才会往%d中输出,因为有多条赋值语句,所以他是个累加过程,直到压栈结束后输出最终得累加值
下面是几组测试样例:
int a;
a=1; printf("%d %d %d %d\n",a,a++,++a,++a); //4 3 4 4
a=1; printf("%d %d %d %d\n",++a,a++,++a,a); //4 2 4 4
a=1; printf("%d %d %d %d\n",++a,a,a++,++a); //4 4 2 4
a=1; printf("%d %d %d %d\n",a++,a++,++a,a++); //4 3 5 1
在这里面有一个a++,和++a两种赋值的语句,它们在printf()中输出时需要注意一下
a++我们都知道是先使用后加一的,那么在printf("%d %d %d %d\n",a,a++,++a,++a);
这里也是一样的,从右向左依次计算值,我们先假设把累加数值暂存在t中,则从右向左依次为
int a=1;
++a a自增1 t=2
++a a自增1 t=3
a++ 先使用(输出3)再自增1 t=4
a 不改变 t=4
所有的a++与a的值都按最终的t输出,所以输出为4 3 4 4
只要遇到a++这种先使用在变化的量优先输出。
再比如a=10; printf("%d %d %d %d\n",a,a++,++a,++a);
代码
因此输出结果为13 12 13 13
以上就是我总结的判断在printf()中a++与++a的输出问题。
最后再补上一组测试用例:
int a;
a=10; printf("%d %d %d %d\n",a--,a++,++a,--a);
a=10; printf("%d %d %d %d\n",++a,a++,a,a--);
a=10; printf("%d %d %d %d\n",a++,a--,a++,++a);
a=10; printf("%d %d %d %d\n",a++,a,++a,a++);
输出结果分别为
//11 10 10 10
//11 9 11 10
//11 12 11 12
//12 13 13 10
最后说明一下因为目前博主只是小菜鸟一枚,很多东西都不懂,只是随便写写,希望我写的这篇文章对你能有帮助。
2021-3-22 更新;
printf函数压栈问题,与编译器以及最终编译时的选项参数(如gcc -O1 … )都有关。因此,单纯的讨论此题的输出内容,我个人认为没有什么意义,但是通过分析这些输出结果进而分析出其具体的执行过程,还是很有意思的。
不同的编译器上生成的汇编指令,都各自有针对其代码优化的地方。(我们可以通过汇编代码分析程序究竟做了哪些操作。)
下面展示一个示例程序,每一种输出情况我将使用画图板简单的模拟器执行过程。
代码:
#include <iostream>
using namespace std;
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* p = arr;
printf("%d %d %d\n", *(p++), *(p++), *(++p));
//printf("%d %d %d %d\n", *p, *(p++), *(p++), *(++p));
return 0;
}
情况一
在VS编译器上,使用debug模式输出:
在剖析其原理时,我们需明晰后置加加的实现原理。其“先使用后加一”意为,先返回一个保存当前值的临时变量,再自身自增1 。(ps:在c语言中前置++/–与后置++/–都视为临时量,不可做左值。在c++中只有后置++/–视为临时量,不可做左值。)
//后置++
T operator++(int) //占位符,表示后置++
{
T tmp = this;
this = this + 1; //执行递增
return tmp; //返回临时值
}
注:因为printf()函数是可变参数编程,参数不确定个数,因此采用自右向左的入栈方式。(其他函数的参数入栈方式并没有明确规定,一般而言也是从右往左入栈的。 而具体的根据编译器和调用约定的不同,可能会有所不同。)
在下图中参数的入栈均遵循自右向左入栈。输出时按照参数的顺序(自左到右输出),我们从(图左)栈视图中,自上向下为输出的顺序。如该图表示输出 3,2,4 。
情况二
在VS编译器上,使用release模式输出:
情况三
使用minGW-g++编译器:
输出: