最近在百度知道上看到的两道题目而引发的,先看题。
题一:
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
其实不然,最终结果还是先算的++b,再算的a+b,继续看反汇编:
扫描二维码关注公众号,回复:
2788015 查看本文章
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)