分析从C#生成的MSIL代码

时间:2012-09-22 16:00:08

标签: c# il

我有以下功能:

public string MyPhrase(int val)
{
    if ((val %3 == 0) && (val % 6 == 0))
        return "Fizz Bang";
    if (val % 3 == 0)
        return "Fizz";
    if (val % 6 == 0)
        return "Bang";
    return "";
}

编译完并用IlDasm查看后,我得到了这个输出:

IL_0000:  ldarg.1
IL_0001:  ldc.i4.3
IL_0002:  rem
IL_0003:  brtrue.s   IL_0010

IL_0005:  ldarg.1
IL_0006:  ldc.i4.6
IL_0007:  rem
IL_0008:  brtrue.s   IL_0010

IL_000a:  ldstr      "Fizz Bang"
IL_000f:  ret

IL_0010:  ldarg.1
IL_0011:  ldc.i4.3
IL_0012:  rem
IL_0013:  brtrue.s   IL_001b

IL_0015:  ldstr      "Fizz"
IL_001a:  ret

IL_001b:  ldarg.1
IL_001c:  ldc.i4.6
IL_001d:  rem
IL_001e:  brtrue.s   IL_0026

IL_0020:  ldstr      "Bang"
IL_0025:  ret

IL_0026:  ldstr      ""
IL_002b:  ret

this page看,如果属实,brtrue会分支。让我感到困惑的是IL_0003行。它说它应该分支到行IL_0010如果它是真的。在我的C#代码中,我使用&&来比较两个表达式,然后我的程序流应该跳转到下一个if。它似乎倒退了。从发布的MSIL代码来看,它似乎检查我的操作是否为真,如果是,它跳转到我的下一个if块,这在逻辑上是错误的。有人可以解释我错过的东西吗?

3 个答案:

答案 0 :(得分:4)

这是短路评估的副作用用于&&运营商。如果左侧是假的,那么承诺不会评估运算符的右侧表达式。因此,如果REM操作码返回非零结果,则会看到它跳过val%6 == 0表达式并返回“Fizz Bang”语句。

答案 1 :(得分:1)

brtrue.s 如果堆栈上的值不为零,则将控制转移到给定目标。

因此,在您的IL代码IL_0003中,转移控件为IL_0010。表示(val%3 == 0)条件返回false。你在条件&&的第一个条件if ((val %3 == 0) && (val % 6 == 0))中使用(val % 3 == 0)所以,在第一个条件IL_0005: ldarg.1 IL_0006: ldc.i4.6 IL_0007: rem IL_0008: brtrue.s IL_0010 上返回false,第二个条件不会检查

IL_0010

并控制转移到IL_0010: ldarg.1 IL_0011: ldc.i4.3 IL_0012: rem IL_0013: brtrue.s IL_001b

{{1}}

请查看此信息以获取更多信息:http://weblogs.asp.net/kennykerr/archive/2004/09/23/introduction-to-msil-part-6-common-language-constructs.aspx

答案 2 :(得分:0)

这个blok在开始比较之前加载来自Stack的参数数据

因此跳转到加载数据的这一部分是正常的

IL_0010:  ldarg.1
IL_0011:  ldc.i4.3
...