C语言 printf计算顺序和压栈顺序初探

不同编译器产生的结果不同,本文测试环境为VS2013和VC6.

                                                                                                                                                              

先看以下代码:

int x = 3;
printf("%d%d%d%d%d%d", x, x++, x, ++x, x--, x);

VS2013输出结果:434434  

VC6输出结果:444433


那么问题来了:

(1)两个编译器printf的压栈顺序和计算顺序是怎样的?

(2)两个编译器如何对x++,++x处理的?

                                                                                                                                                              


VS2013反汇编代码

        int x = 3;
010352CE  mov         dword ptr [x],3  
	printf("%d%d%d%d%d%d", x, x++, x, ++x, x--, x);
//x--
010352D5  mov         eax,dword ptr [x]  
010352D8  dword       ptr [ebp-0D0h],eax //此时x = 3 ,将 x 的值存在 ebp-0d0h 这个相对地址中
010352DE  mov         ecx,dword ptr [x]  
010352E1  sub         ecx,1  
010352E4  mov         dword ptr [x],ecx  
	printf("%d%d%d%d%d%d", x, x++, x, ++x, x--, x);
//++x  直接在edx完成
010352E7  mov         edx,dword ptr [x] 
010352EA  add         edx,1
010352ED  mov         dword ptr [x],edx //x = 3
//x++ 
010352F0  mov         eax,dword ptr [x]  
010352F3  mov         dword ptr [ebp-0D4h],eax //此时x = 3 ,将 x 的值存在 ebp-0d4h 这个相对地址中
010352F9  mov         ecx,dword ptr [x]  
010352FC  add         ecx,1
010352FF  mov         dword ptr [x],ecx 
//压栈
01035302  mov         esi,esp  
01035304  mov         edx,dword ptr [x]  
01035307  push        edx //4
01035308  mov         eax,dword ptr [ebp-0D0h]  
0103530E  push        eax //ebp-0D0h 地址中值为 3
0103530F  mov         ecx,dword ptr [x]  
01035312  push        ecx //4
01035313  mov         edx,dword ptr [x]  
01035316  push        edx //4
01035317  mov         eax,dword ptr [ebp-0D4h]  
0103531D  push        eax //ebp-0D4h 地址中值为 3
0103531E  mov         ecx,dword ptr [x]  
01035321  push        ecx //4
01035322  push        103CA54h  
01035327  call        dword ptr ds:[1040184h]  
结果 434434
VC6反汇编代码

        int x = 3
00401028  movd        word ptr [ebp-4],3
	printf("%d%d%d%d%d%d",x,x++,x,++x,x--,x);
0040102F  mov         eax,dword ptr [ebp-4]
00401032  push        eax //x = 3
//x--
00401033  mov         ecx,dword ptr [ebp-4]
00401036  mov         dword ptr [ebp-8],ecx //ebp-8 值为3
00401039  mov         edx,dword ptr [ebp-8]
0040103C  push        edx //x = 3
//++x 在eax完成
0040103D  mov         eax,dword ptr [ebp-4]
00401040  add         eax,1
00401043  mov         dword ptr [ebp-4],eax
00401046  mov         ecx,dword ptr [ebp-4]
00401049  push        ecx //x = 4
0040104A  mov         edx,dword ptr [ebp-4]
0040104D  push        edx //x = 4
//x++
0040104E  mov         eax,dword ptr [ebp-4]
00401051  mov         dword ptr[ebp-0Ch],eax //ebp-0ch 值为4
00401054  mov         ecx,dword ptr[ebp-0Ch]
00401057  push        ecx //x = 4
00401058  mov         edx,dword ptr [ebp-4]
0040105B  push        edx //x = 4
0040105C  push        offset string"%d%d%d%d%d%d" (0042201c)
00401061  mov         eax,dword ptr [ebp-4] //操作的是x值
00401064  add         eax,1 
00401067  mov         dword ptr [ebp-4],eax
0040106A  mov         ecx,dword ptr [ebp-4] //同上
0040106D  sub         ecx,1
00401070  mov         dword ptr [ebp-4],ecx
00401073  call        printf (004010b0)	
结果 444433

                                                                                                                                                              

由上反汇编代码,我们可以得出以下结论:

(1)两个编译器的压栈顺序相同:从右到左  计算顺序:因编译器而异,与压栈顺序无关。

(2)++x: 两编译器的处理方式相同,直接对寄存器进行值进行修改。

         x++:VS2013将x值先保存在某个相对地址中,再对现有x值累加计算,并继续其他运算,最后将存储的x值压入栈中;VC6直接将x值压入栈,并进行其他运算,压栈完成以后再对x值进行累加计算。

总结:结果不同的原因是由于两个编译器对x++处理方式的不同,在比较x++和++x的实现方式时,我们发现x++会在实现中产生一个副本,如果这个副本足够大的时候,在一定程度上会影响计算的效率,应此++x应该优先使用。


以上只是个人观点,有不合理之处欢迎各位指点。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值