2

我有以下功能:

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

从查看此页面brtrue如果为真,将分支。让我困惑的是这条线IL_0003。它的说法是,IL_0010如果它是真的,它应该分支到线。不过,在我的 C# 代码中,我使用 an&&来比较两个表达式,然后我的程序流应该跳转到下一个if. 好像倒退了。从发布的 MSIL 代码来看,它似乎在检查我的操作是否正确,如果是,则跳转到我的下一个if块,这在逻辑上是错误的。有人可以解释我错过了什么吗?

4

3 回答 3

4

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

于 2012-09-22T16:06:41.963 回答
1

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

因此,在您的 IL 代码IL_0003中,将控制权转移到IL_0010. 表示 (val % 3 == 0) 条件返回 false。你&&在第一个 if 条件中使用了,if ((val %3 == 0) && (val % 6 == 0))所以在第一个条件下(val % 3 == 0) 返回 false,第二个条件不会检查

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

和控制转移到IL_0010

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

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

于 2012-09-22T16:21:52.867 回答
0

这个块从堆栈加载参数数据,然后开始比较

所以跳转到加载数据这一段很正常

IL_0010:  ldarg.1
IL_0011:  ldc.i4.3
...
于 2012-09-22T16:06:20.293 回答