青牛笔试
这段时间师兄都忙着找工作,一场接一场,有时候一天赶好几个场子,时间来不及就经常让我去帮他们笔试一下,我也借此锻炼一下,看看笔试题的难度,昨天接师兄通知,去青牛笔试,C/C++方向,技术试题中有一道题我想在这里说下,原题大致如下:
#include<stdio.h>
#define pt(x) (x*x)
int main()
{
int i=3;
int j=0,k=0;
j= pt(i++);
k= pt(++i);
printf("j= %d,k= %d\n",j,k);
}
问:输出的结果是什么?
答案是:j=9,k=49
第一个答案j=9还好理解,k=49 完全想不通,遇到这种题,就算知道正确答案,但是想又想不通为什么就让人郁闷了,而且很多人会说编译器不同结果也不一样,我是用GCC 来跑一遍得出的结果:j=9,k=49 。
那么如何理解,对于这种题,建议大家出查源码的汇编代码,就会很清楚计算机是如何得到这个结果的,我们贴下起汇编代码,如下:
相对应的汇编代码:
#include<stdio.h>
#define pt(x) (x*x)
int main()
{
00CA1380 push ebp
00CA1381 mov ebp,esp
00CA1383 sub esp,0E4h
00CA1389 push ebx
00CA138A push esi
00CA138B push edi
00CA138C lea edi,[ebp-0E4h]
00CA1392 mov ecx,39h
00CA1397 mov eax,0CCCCCCCCh
00CA139C rep stos dword ptr es:[edi]
int i=3;
00CA139E mov dword ptr [i],3 //把 3赋值给 i
int j=0,k=0;
00CA13A5 mov dword ptr [j],0 //初始化 j,k变量为 0
00CA13AC mov dword ptr [k],0
j= pt(i++);
00CA13B3 mov eax,dword ptr [i] //先把 i的值取出到寄存器 eax中
00CA13B6 imul eax,dword ptr [i] //把i的值取出与原寄存器值相乘,结果保存在寄存器中
00CA13BA mov dword ptr [j],eax //把寄存器的值 9赋值给 j
00CA13BD mov ecx,dword ptr [i] //最后把 i取出到寄存器中,加一
00CA13C0 add ecx,1
00CA13C3 mov dword ptr [i],ecx //再赋值给 i ,此时 i 为 4
00CA13C6 mov edx,dword ptr [i] //同理与上,再对 i取出加一重新赋值给 i
00CA13C9 add edx,1
00CA13CC mov dword ptr [i],edx //此时 i为 5
printf("i= %d\n",i);
00CA13CF mov esi,esp
00CA13D1 mov eax,dword ptr [i]
00CA13D4 push eax
00CA13D5 push offset string "i= %d\n" (0CA574Ch)
00CA13DA call dword ptr [__imp__printf (0CA82B0h)]
00CA13E0 add esp,8
00CA13E3 cmp esi,esp
00CA13E5 call @ILT+295(__RTC_CheckEsp) (0CA112Ch)
k= pt(++i);
00CA13EA mov eax,dword ptr [i] //首先将 i取出到寄存器 eax
00CA13ED add eax,1 //加一
00CA13F0 mov dword ptr [i],eax //将寄存器 eax的值赋值给变量 i,此时 i 的值为6
00CA13F3 mov ecx,dword ptr [i]
00CA13F6 add ecx,1
00CA13F9 mov dword ptr [i],ecx //同理,此时 i的值为7
00CA13FC mov edx,dword ptr [i] //将 i 值取出到寄存器
00CA13FF imul edx,dword ptr [i] //再将 i 值与寄存器值相乘,eax为 49
00CA1403 mov dword ptr [k],edx //将 eax的值赋值给 K
printf("j= %d,k= %d\n",j,k);
00CA1406 mov esi,esp
00CA1408 mov eax,dword ptr [k]
00CA140B push eax
00CA140C mov ecx,dword ptr [j]
00CA140F push ecx
00CA1410 push offset string "j= %d,k= %d\n" (0CA573Ch)
00CA1415 call dword ptr [__imp__printf (0CA82B0h)]
00CA141B add esp,0Ch
00CA141E cmp esi,esp
00CA1420 call @ILT+295(__RTC_CheckEsp) (0CA112Ch)
}结论:GCC 编译器在处理表达式: i++*i++ 时,先取 i 的值,进行运算,再对 i 两次加加操作,而对表达式:++i *++i 时,先对 i两次加加操作,再相乘;现在明白了吧?