IL开关指令
IL switch instruction
我正在研究从此 C# 代码生成的 IL 代码 (RELEASE):
int a = Convert.ToInt32(Console.ReadLine());
switch(a)
{
case 1: Console.WriteLine(); break;
case 2: Console.WriteLine(); break;
case 3: Console.WriteLine(); break;
case 15: Console.WriteLine(); break;
default: Console.WriteLine(); break;
}
IL:
//Why not "switch(IL_0026, IL_002c, IL_0032, IL_0038)"?
IL_000e: switch (IL_0026, IL_002c, IL_0032)
IL_001f: ldloc.0
IL_0020: ldc.i4.s 15
IL_0022: beq.s IL_0038
IL_0024: br.s IL_003e
IL_0026: call void [System.Console]System.Console::WriteLine()
IL_002b: ret
IL_002c: call void [System.Console]System.Console::WriteLine()
IL_0031: ret
IL_0032: call void [System.Console]System.Console::WriteLine()
IL_0037: ret
IL_0038: call void [System.Console]System.Console::WriteLine()
IL_003d: ret
IL_003e: call void [System.Console]System.Console::WriteLine()
IL_0043: ret
为什么 IL 中的“开关”使用序列 (1,2,3...n+1) 并且不添加其他值(例如:对于 15 生成的 3 条指令(001f、0020、0022))
//Why not "switch(IL_0026, IL_002c, IL_0032, IL_0038)"?
因为如果a
的值是4,而不是15,就会跳转到第4个标签。switch
中的跳转目标对应连续的值 的测试值。
为了使用 switch
并且没有 15
的额外特殊情况,它需要是:
switch(IL_0026, IL_002c, IL_0032, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_0038)
(希望我没记错)
这将是一个更大的跳跃 table。
我总是建议您查看 Reflection.Emit
的文档以了解您正在查看的说明,例如OpCodes.Switch
,以确保您了解指令的作用。
The switch instruction pops a value off the stack and compares it, as an unsigned integer, to N
. If value is less than N
, execution is transferred to the target indexed by value, where targets are numbered from 0 (for example, a value of 0 takes the first target, a value of 1 takes the second target, and so on).
我正在研究从此 C# 代码生成的 IL 代码 (RELEASE):
int a = Convert.ToInt32(Console.ReadLine());
switch(a)
{
case 1: Console.WriteLine(); break;
case 2: Console.WriteLine(); break;
case 3: Console.WriteLine(); break;
case 15: Console.WriteLine(); break;
default: Console.WriteLine(); break;
}
IL:
//Why not "switch(IL_0026, IL_002c, IL_0032, IL_0038)"?
IL_000e: switch (IL_0026, IL_002c, IL_0032)
IL_001f: ldloc.0
IL_0020: ldc.i4.s 15
IL_0022: beq.s IL_0038
IL_0024: br.s IL_003e
IL_0026: call void [System.Console]System.Console::WriteLine()
IL_002b: ret
IL_002c: call void [System.Console]System.Console::WriteLine()
IL_0031: ret
IL_0032: call void [System.Console]System.Console::WriteLine()
IL_0037: ret
IL_0038: call void [System.Console]System.Console::WriteLine()
IL_003d: ret
IL_003e: call void [System.Console]System.Console::WriteLine()
IL_0043: ret
为什么 IL 中的“开关”使用序列 (1,2,3...n+1) 并且不添加其他值(例如:对于 15 生成的 3 条指令(001f、0020、0022))
//Why not "switch(IL_0026, IL_002c, IL_0032, IL_0038)"?
因为如果a
的值是4,而不是15,就会跳转到第4个标签。switch
中的跳转目标对应连续的值 的测试值。
为了使用 switch
并且没有 15
的额外特殊情况,它需要是:
switch(IL_0026, IL_002c, IL_0032, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_003e, IL_0038)
(希望我没记错)
这将是一个更大的跳跃 table。
我总是建议您查看 Reflection.Emit
的文档以了解您正在查看的说明,例如OpCodes.Switch
,以确保您了解指令的作用。
The switch instruction pops a value off the stack and compares it, as an unsigned integer, to
N
. If value is less thanN
, execution is transferred to the target indexed by value, where targets are numbered from 0 (for example, a value of 0 takes the first target, a value of 1 takes the second target, and so on).