i++和printf不得不说的故事

#include<stdio.h>

int main()
{
	int i = 0;
	printf("%d,%d,%d\n", i++, --i, i++);

	return 0;
}

今天看到了一段很短的代码,问结果?


相信很多人像我一样,感觉就是小case吧?都不用画图分析,在脑袋中过一遍就得出了答案。我们知道c语言压参顺序是从右向左,那么这里涉及到与++和--的结合。这个运算也是从右向左的顺序。我脑海的中的处理过程:
1:将i(此时为0)压入栈中,此后做+1运算后将1赋给i。
2:将i做-1运算,也就是1-1=0,然后将0值赋给i,然后将i(此时为0)压入栈中。
3:类似步骤1,将i(此时为0)压入栈中,然后做+1运算后将1赋给i。

可以看到,上面三步压入栈中的数据为0,0,0。也就是我们预期的结果应该是0,0,0。OK,接下来只需要验证我们的结果就就可以啦~

嗯?结果和预想的不一样?wtf?看到这个结果的时候,我真的认为自己之前的知识是不是出了什么问题,再去看了看++和--的知识发现没有问题啊,可是结果运用之前的知识分析就是不对啊。~那到底是那里出问题了呢?~这个时候就需要我们去调试代码看看它具体的处理过程了。下面是它的汇编代码。


printf("%d,%d,%d\n", i++, --i, i++);
00DE1805  mov         eax,dword ptr [i]  
00DE1808  mov         dword ptr [ebp-0D0h],eax  
00DE180E  mov         ecx,dword ptr [i]  
00DE1811  add         ecx,1  
00DE1814  mov         dword ptr [i],ecx  
00DE1817  mov         edx,dword ptr [i]  
00DE181A  sub         edx,1  
00DE181D  mov         dword ptr [i],edx  
00DE1820  mov         eax,dword ptr [i]  
00DE1823  mov         dword ptr [ebp-0D4h],eax  
00DE1829  mov         ecx,dword ptr [i]  
00DE182C  add         ecx,1  
00DE182F  mov         dword ptr [i],ecx  
00DE1832  mov         edx,dword ptr [ebp-0D0h]  
00DE1838  push        edx  
00DE1839  mov         eax,dword ptr [i]  
00DE183C  push        eax  
00DE183D  mov         ecx,dword ptr [ebp-0D4h]  
00DE1843  push        ecx 


分析这段汇编,可以看出它的处理步骤大概如下:

00DE1805  mov         eax,dword ptr [i]  
00DE1808  mov         dword ptr [ebp-0D0h],eax  
00DE180E  mov         ecx,dword ptr [i]  
00DE1811  add         ecx,1  
00DE1814  mov         dword ptr [i],ecx  
1:将i(此时为0)压入eax寄存器,将eax内的值赋给一个临时量1(地址为[ebp-0D0h]),然后将i(此时为0)压入ecx寄存器,ecx+1运算后将值赋给i(此时i为1)。(对应汇编的2-6)
00DE1817  mov         edx,dword ptr [i]  
00DE181A  sub         edx,1  
00DE181D  mov         dword ptr [i],edx

2:将i(此时为1)压入edx寄存器,edx-1后将值赋给i(此时i为0)。(对应汇编的7-9)

00DE1820  mov         eax,dword ptr [i]  
00DE1823  mov         dword ptr [ebp-0D4h],eax  
00DE1829  mov         ecx,dword ptr [i]  
00DE182C  add         ecx,1  
00DE182F  mov         dword ptr [i],ecx  

3:将i(此时为0)压入eax寄存器,将eax内的值赋给一个临时量2(地址为[ebp-0D4h]),然后将i(此时为0)压入ecx寄存器,ecx+1运算后将值赋给i(此时i为1)。(对应汇编10-14)

00DE1832  mov         edx,dword ptr [ebp-0D0h]  
00DE1838  push        edx  
00DE1839  mov         eax,dword ptr [i]  
00DE183C  push        eax  
00DE183D  mov         ecx,dword ptr [ebp-0D4h]  
00DE1843  push        ecx 

4:接下来是压参过程,依次压入临时量1(地址为[ebp-0D0h]),i(此时为0),临时量2(地址为[ebp-0D4h])。


总结:
可以看到上述过程在处理过程中并没有像我们想象的那样,处理一个参数压入一个参数。i++是先将值保存在一个临时量中,然后做运算改变i的值。而--i,是先做运算改变i的值,注意这里是和预想结果不一样的重点,它做运算后将值赋给i并不会将值保存在临时量中,而是等所有运算结束后压入i的值。这里就引发一个问题,如果--i不是最后一个做运算的,那么它的后续运算(也就是第一个参数i++)将会改变i的值。做完运算后统一压参数的时候,i++都是压入它们未做运算前的临时量,所以它们和预想的结果一致。而--i是等所有运算结束后压入i值,如果这个过程是独立的,没有其他运算参与那么没有问题,可是这里因为还有后续的i++(它最终将i的值运算为0),就导致了结果和预想的不一致。


解决方案:
压--i这个参数可以参考i++的过程,如果它在运算结束后将值赋给一个临时量,在所有运算结束后,压入这个临时量,那么逻辑过程就应该和预想的一致了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值