朋友公司招聘用的一套C#基础面试题,10个码农8个错2个蒙,我也跳坑了…
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了朋友公司招聘用的一套C#基础面试题,10个码农8个错2个蒙,我也跳坑了…相关的知识,希望对你有一定的参考价值。
朋友公司的一套面试题,很有意思,参见如下代码:
class Program
static void Main(string[] args)
var t = Num();
Console.WriteLine(t);
Console.ReadLine();
static int Num()
int i = 10;
try
return i;
finally
i = 11;
Console.WriteLine($"i=i");
请问这段代码会输出什么?相信有一点编程经验的朋友都知道,答案是:output: i=11
,接下来的一个问题是这个 Num()
方法的返回值是多少, 10
还是 11
?相信有很多朋友就有点迷糊了,那答案是多少呢?在不运行程序的情况下,我们从 IL
和 汇编角度
来寻找答案。
一:IL 上寻找答案
要想看 IL,可以用 ILSpy 反编译一下。
.method private hidebysig static
int32 Num () cil managed
// Method begins at RVA 0x2074
// Code size 39 (0x27)
.maxstack 2
.locals init (
[0] int32 i,
[1] int32
)
IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
.try
IL_0004: nop
IL_0005: ldloc.0
IL_0006: stloc.1
IL_0007: leave.s IL_0025
// end .try
finally
IL_0009: nop
IL_000a: ldc.i4.s 11
IL_000c: stloc.0
IL_000d: ldstr "i=0"
IL_0012: ldloc.0
IL_0013: box [mscorlib]System.Int32
IL_0018: call string [mscorlib]System.String::Format(string, object)
IL_001d: call void [mscorlib]System.Console::WriteLine(string)
IL_0022: nop
IL_0023: nop
IL_0024: endfinally
// end handler
IL_0025: ldloc.1
IL_0026: ret
// end of method Program::Num
对比 return i
生成的 IL 代码,它的做法是将 i
保存到了一个临时变量 loc.1
处,最后将 loc.1
处的变量返回出去,我们很惊讶的发现 finally
块中并没有对 loc.1
处的变量赋值,也就是没有 stloc.1
指令,综合下来结果应该是 10, 而不是 11。
不知道可有朋友发现,这里的跳转指令 IL_0007: leave.s IL_0025
,貌似直接跳过了 finally
块,那到底有没有执行呢?这个从 IL 上看不出,只能从 汇编角度 看啦。
二:查看汇编
接下来祭出windbg,汇编代码如下:
0:006> !U /d 008608a8
Normal JIT generated code
ConsoleApp1.Program.Num()
Begin 008608a8, size aa
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 23:
008608d4 c745e40a000000 mov dword ptr [ebp-1Ch],0Ah
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 26:
008608db 90 nop
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 27:
008608dc 8b45e4 mov eax,dword ptr [ebp-1Ch]
008608df 8945e0 mov dword ptr [ebp-20h],eax
008608e2 90 nop
008608e3 c745ec00000000 mov dword ptr [ebp-14h],0
008608ea c745f0fc000000 mov dword ptr [ebp-10h],0FCh
008608f1 6849098600 push 860949h
008608f6 eb00 jmp 008608f8
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 30:
008608f8 90 nop
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 31:
008608f9 c745e40b000000 mov dword ptr [ebp-1Ch],0Bh
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 32:
00860900 b9a8429778 mov ecx,offset mscorlib_ni+0x142a8 (789742a8) (MT: System.Int32)
00860905 e8ea27daff call 006030f4 (JitHelp: CORINFO_HELP_NEWSFAST)
0086090a 8945dc mov dword ptr [ebp-24h],eax
0086090d 8b0544235d03 mov eax,dword ptr ds:[35D2344h] ("i=0")
00860913 8945d4 mov dword ptr [ebp-2Ch],eax
00860916 8b45dc mov eax,dword ptr [ebp-24h]
00860919 8b55e4 mov edx,dword ptr [ebp-1Ch]
0086091c 895004 mov dword ptr [eax+4],edx
0086091f 8b45dc mov eax,dword ptr [ebp-24h]
00860922 8945d0 mov dword ptr [ebp-30h],eax
00860925 8b4dd4 mov ecx,dword ptr [ebp-2Ch]
00860928 8b55d0 mov edx,dword ptr [ebp-30h]
0086092b e820d74c78 call mscorlib_ni!System.String.Format(System.String, System.Object)$##6000545 (78d2e050)
00860930 8945d8 mov dword ptr [ebp-28h],eax
00860933 8b4dd8 mov ecx,dword ptr [ebp-28h]
00860936 e829465b78 call mscorlib_ni!System.Console.WriteLine(System.String)$##6000B79 (78e14f64)
0086093b 90 nop
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 33:
0086093c 90 nop
0086093d 58 pop eax
0086093e ffe0 jmp eax
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 34:
00860940 8b45e0 mov eax,dword ptr [ebp-20h]
00860943 8d65fc lea esp,[ebp-4]
00860946 5f pop edi
00860947 5d pop ebp
00860948 c3 ret
D:\\net5\\ConsoleApp1\\ConsoleApp1\\Program.cs @ 22:
00860949 c745f000000000 mov dword ptr [ebp-10h],0
00860950 ebee jmp 00860940
为了方便比对,我再把代码行数给截出来。
一般函数的返回值都是放在 eax
中,所以重点关注下 eax
的赋值部分,仔细观察它的路径大概就是下面四句代码:
mov dword ptr [ebp-1Ch],0Ah
mov eax,dword ptr [ebp-1Ch]
mov dword ptr [ebp-20h],eax
mov eax,dword ptr [ebp-20h]
也就是说,最后的 eax 还是当初的 0Ah= 10
, 也和 IL 反映出来的一致,return 操作的底层会将返回值放到一个 临时区域 = ebp-20h
中,最后返回 临时区域 中的值。
再回到刚才 IL 部分的疑问,从上面的 jmp 008608f8
指令看,return 的下一步就直接进了 finally
块,最后执行 RET
弹出下一行代码指令到 EIP 中完成方法体的执行,大概就是这个样子。
以上是关于朋友公司招聘用的一套C#基础面试题,10个码农8个错2个蒙,我也跳坑了…的主要内容,如果未能解决你的问题,请参考以下文章