我只是在尝试使用IL,因为我正在从事代码注入的工作。我被要求分析代码并涵盖各种情况。
遗憾的是,如果最后的指令在if子句中,那么在末尾插入方法调用是行不通的,因为调用包含在括号中。
现在我一直在分析if-code如何被翻译成IL,我对如何做到这一点感到有点困惑。显然,编译器反转了if。这是因为性能原因吗?如果是这样的话,这会在多大程度上提高性能?
你自己看一下:
string test;
Random rnd = new Random();
bool b = rnd.Next(0, 10) == 3;
if (b)
{
// TRUE
test = "True branch";
// END TRUE
}
else
{
// FALSE
test = "False branch";
//END FALSE
}这是输出:
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Random::.ctor()
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.0
IL_0009: ldc.i4.s 10
IL_000b: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
IL_0010: ldc.i4.3
IL_0011: ceq
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
IL_001a: brtrue.s IL_0026
IL_001c: nop
IL_001d: ldstr "True branch"
IL_0022: stloc.0
IL_0023: nop
IL_0024: br.s IL_002e
IL_0026: nop
IL_0027: ldstr "False branch"
IL_002c: stloc.0
IL_002d: nop
IL_002e: ret正如您所看到的,在随机结果与常量3进行比较之后,它再次与0进行比较,从而颠倒了与if (false)等价的结果。
这是什么原因呢?因为你需要额外的指令,所以它的性能不是更差吗?这种情况经常发生吗?
发布于 2015-03-10 21:08:59
您现在看到的是调试版本。将其更改为发布版本,它将使用brfalse.s
IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: ldc.i4.0
IL_0008: ldc.i4.s 10
IL_000a: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
IL_000f: ldc.i4.3
IL_0010: ceq
IL_0012: stloc.2
IL_0013: ldloc.2
IL_0014: brfalse.s IL_001e
IL_0016: ldstr "True branch"
IL_001b: stloc.0
IL_001c: br.s IL_0024
IL_001e: ldstr "False branch"
IL_0023: stloc.0我添加了一个Console.WriteLine,否则test变量将被删除。
IL_0024: ldloc.0
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ret因此,Debug和release之间的区别在于:
// Debug
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
IL_001a: brtrue.s IL_0026vs
// Release
IL_0014: brfalse.s IL_001e因此,对于Debug版本,有四条额外的指令,以及一个“反向”if。
首先,我要说的是,C#编译器试图使代码保持与编写时相同的顺序。所以首先是"true“分支,然后是"false”分支。
好的..。我在做一个假设...
假设问题出现在Debug模式中...在调试模式下,代码必须很详细...非常冗长。所以
if (b)被翻译成
if (b == true)遗憾的是,true是“除-0以外的任何值”,所以它更容易编写
if (!(b == false))因为false是"0“。但这是在调试模式下编写的:-)只有调试模式使用temp变量
作为
// bool temp = b == false;
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3和
// if (temp) // go to else branch
IL_001a: brtrue.s IL_0026发布于 2015-03-10 21:14:39
编译器没有反转任何东西。请注意,if语句的两个分支在IL中的顺序与它们在源代码中的顺序相同。您可以从两个字符串的顺序中看出这一点。
当布尔值为false时,brtrue的使用只是用于分支的自然IL。测试布尔值是否为真意味着将其与0进行比较。值为0为false,其他值均为true。
因此,编译器发出IL来与0进行比较。如果比较为真,即如果布尔值具有序数值0,则布尔值为假。所以,如果分支等于零,就意味着分支,如果布尔值为false。这是对0的ceq,然后是brtrue。
也就是说,值得指出的是,编译调试性能并不是问题。编译器想要编写代码,以便调试器可以检查变量。如果您对性能感兴趣,那么您必须查看发布版本中的IL。当你这样做的时候,你会看到完全不同的代码。
https://stackoverflow.com/questions/28964329
复制相似问题