printf压栈顺序之 i++ 及 ++i
i++ 与 ++i 的不同
1 i=1; printf("%d %d\n",i,i++); //结果 2 1
2 i=1; printf("%d %d\n",i++,i); //结果 1 2
3 i=1; printf("%d %d %d\n",i,i++,i); //结果 2 1 2
4 i=1; printf("%d %d %d %d\n",i,++i,i++,i); //结果 3 3 1 3
解析:
已知前提:
- printf输出时,压栈顺序为从右往左,也就是说从右往左的计算;
- 入栈时先进后出,先进入的在栈的高地址,后进入的在栈的低地址;
- printf后面的表达式,比如i++, 此操作为计算,”计算“ 是计算,但是不等于“输出”的结果;
- i++的结果,是有ebp寻址函数栈空间来记录中间结果的,在最后给printf压栈的时候,再从ebp栈中把中间结果取出来压入printf分配的栈中;
- ++i的结果,是直接寄存器进行自增操作,然后把该寄存器的地址压入printf分配的栈中。
i++是先计算后自加,而++i是先自加后计算。
1 int main() 2 { 3 int i = 0; 4 //i++ = 100;//直接报错,编译出错: error C2106: “=”: 左操作数必须为左值 5 ++i=100;//通过,没有错误 6 printf("%d", i);//直接打印100 7 return 0; 8 }
从上面的代码情况可以认为编译器在处理i++和++i的方式不同
- i++完成之后返回的是右值也就是一个常量
- ++i完成之后返回的是左值也就是i的内存,对++i赋值相当于给i赋值
结论:printf压栈的时候,i++其实压的是ebr中间结果的值,也就是一个常量。而++i 因为计算后的结果是一个左值,故会将i对应的地址进行压栈。
例题说明
i=1; printf("%d %d %d %d\n",i,++i,i++,i); //结果 3 3 1 3
++i 是直接真值进行自加,而 i++ 则是通过在ebr中存放的临时副本进行加1后再赋值给i
栈 | 运算式 | 真值(寄存器中) | 副本(ebr中) |
低位 | i | 3 | |
++i | 3 | ||
i++ | 2 | 1 | |
高位 | i | 1 |
最终 i 的真值为3,i++ 的ebr定值为1, 故最后的输出结果为:3 3 1 3