前++/--和后++/--之坑

最近在百度知道上看到的两道题目而引发的,先看题。

题一:

int fn(int a, int b)
{
	return a + b;
}

int f()
{
	int a = 2, b = 4;
	int c = 0;
	c = a + b, ++b;
	int d = fn(a + b, ++b);
        cout << c << ',' << d << endl;
	return 0;
}

输出结果是什么呢,答案是6,14

第一个的c很好理解,直接就是2+4=6;第二个的d是一个函数返回值,fn的两个实参都是表达式,需要进行一步计算,其实这里考虑的是函数传参顺序的问题,传参顺序是

自右向左的,所以先算++b,再算a+b,这个程序跳转到反汇编可以证明这一点:

	int d = fn(a+b,++b);
00A5C005  mov         eax,dword ptr [b]
00A5C008  add         eax,1
00A5C00B  mov         dword ptr [b],eax
00A5C00E  mov         ecx,dword ptr [b]
00A5C011  push        ecx  
00A5C012  mov         edx,dword ptr [a]  
00A5C015  add         edx,dword ptr [b]  
00A5C018  push        edx  
00A5C019  call        fn (0A0B668h)  
00A5C01E  add         esp,8  
00A5C021  mov         dword ptr [d],eax 


但真的是这样吗?如果我们将 int d = fn(a + b, ++b);修改为int d = fn(++b,a+b),如果简单按照前面的结论就是:先算a+b,再算++b咯。

其实不然,最终结果还是先算的++b,再算的a+b,继续看反汇编:

	int d = fn(++b,a+b);
0040C005  mov         eax,dword ptr [b]  
0040C008  add         eax,1  
0040C00B  mov         dword ptr [b],eax  
0040C00E  mov         ecx,dword ptr [a]  
0040C011  add         ecx,dword ptr [b]  
0040C014  push        ecx  
0040C015  mov         edx,dword ptr [b]  
0040C018  push        edx  
0040C019  call        fn (03BB668h)  
0040C01E  add         esp,8  
0040C021  mov         dword ptr [d],eax 

具体步骤还是略有区别滴,前面是计算完了++b就直接pushecx了,接着再算a+b,缓存到ecx,再push了,

现在是算完了++b,再算的a+b,缓存+push a+b的值,接着再缓存+push b的值。

对比可以发现,前置++(其实包括后++)的优先级高于函数参数列表的计算优先级。

int d = fn(a + b, ++b);修改为int d = fn(b++,a+b),结果又变了!

	int d = fn(b++, a+b);
000AC005  mov         eax,dword ptr [b]  
000AC008  mov         dword ptr [ebp-0F4h],eax  
000AC00E  mov         ecx,dword ptr [b]  
000AC011  add         ecx,1  
000AC014  mov         dword ptr [b],ecx  
000AC017  mov         edx,dword ptr [a]  
000AC01A  add         edx,dword ptr [b]  
000AC01D  push        edx  
000AC01E  mov         eax,dword ptr [ebp-0F4h]  
000AC024  push        eax  
000AC025  call        fn (05B668h)  
000AC02A  add         esp,8  
000AC02D  mov         dword ptr [d],eax  



题二:

char sz[] = { "1234" };
cout << sz + 2 << ',' << *(sz + 2) << ',' << (*(sz + 2))++ << endl;

输出结果又是什么呢?参看将 int d = fn(a + b, ++b);修改为int d = fn(b++,a+b),这个其实也是函数的调用与实参表达式计算顺序的问题。

cout << sz + 2 << ',' << *(sz + 2) << ',' << (*(sz + 2))++ << endl;
009ABFF9  mov         al,byte ptr [ebp-0Eh]  
009ABFFC  mov         byte ptr [ebp-0D5h],al  
009AC002  mov         cl,byte ptr [ebp-0Eh]  
009AC005  add         cl,1  
009AC008  mov         byte ptr [ebp-0Eh],cl  
009AC00B  mov         esi,esp  
009AC00D  push        95CE14h  
009AC012  movzx       edx,byte ptr [ebp-0D5h]  
009AC019  push        edx  
009AC01A  push        2Ch  
009AC01C  movzx       eax,byte ptr [ebp-0Eh]  
009AC020  push        eax  
009AC021  push        2Ch  
009AC023  lea         ecx,[ebp-0Eh]  
009AC026  push        ecx  
009AC027  mov         edx,dword ptr ds:[0AB01ACh]  
009AC02D  push        edx  
009AC02E  call        std::operator<<<std::char_traits<char> > (095C559h)  
009AC033  add         esp,8  
009AC036  push        eax  
009AC037  call        std::operator<<<std::char_traits<char> > (095D27Eh)  
009AC03C  add         esp,8  
009AC03F  push        eax  
009AC040  call        std::operator<<<std::char_traits<char> > (095D27Eh)  
009AC045  add         esp,8  
009AC048  push        eax  
009AC049  call        std::operator<<<std::char_traits<char> > (095D27Eh)  
009AC04E  add         esp,8  
009AC051  push        eax  
009AC052  call        std::operator<<<std::char_traits<char> > (095D27Eh)  
009AC057  add         esp,8  
009AC05A  mov         ecx,eax  
009AC05C  call        dword ptr ds:[0AB014Ch]  
009AC062  cmp         esi,esp  
009AC064  call        __RTC_CheckEsp (095C941h)  




猜你喜欢

转载自blog.csdn.net/sirria1/article/details/51744751