首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IL if-比较颠倒

IL if-比较颠倒
EN

Stack Overflow用户
提问于 2015-03-10 20:57:15
回答 2查看 316关注 0票数 2

我只是在尝试使用IL,因为我正在从事代码注入的工作。我被要求分析代码并涵盖各种情况。

遗憾的是,如果最后的指令在if子句中,那么在末尾插入方法调用是行不通的,因为调用包含在括号中。

现在我一直在分析if-code如何被翻译成IL,我对如何做到这一点感到有点困惑。显然,编译器反转了if。这是因为性能原因吗?如果是这样的话,这会在多大程度上提高性能?

你自己看一下:

代码语言:javascript
复制
        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
        }

这是输出:

代码语言:javascript
复制
    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)等价的结果。

这是什么原因呢?因为你需要额外的指令,所以它的性能不是更差吗?这种情况经常发生吗?

EN

回答 2

Stack Overflow用户

发布于 2015-03-10 21:08:59

您现在看到的是调试版本。将其更改为发布版本,它将使用brfalse.s

代码语言:javascript
复制
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变量将被删除。

代码语言:javascript
复制
IL_0024: ldloc.0
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ret

因此,Debug和release之间的区别在于:

代码语言:javascript
复制
// Debug
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3
IL_001a: brtrue.s IL_0026

vs

代码语言:javascript
复制
// Release
IL_0014: brfalse.s IL_001e

因此,对于Debug版本,有四条额外的指令,以及一个“反向”if。

首先,我要说的是,C#编译器试图使代码保持与编写时相同的顺序。所以首先是"true“分支,然后是"false”分支。

好的..。我在做一个假设...

假设问题出现在Debug模式中...在调试模式下,代码必须很详细...非常冗长。所以

代码语言:javascript
复制
if (b)

被翻译成

代码语言:javascript
复制
if (b == true)

遗憾的是,true是“除-0以外的任何值”,所以它更容易编写

代码语言:javascript
复制
if (!(b == false))

因为false是"0“。但这是在调试模式下编写的:-)只有调试模式使用temp变量

作为

代码语言:javascript
复制
// bool temp = b == false;
IL_0015: ldc.i4.0
IL_0016: ceq
IL_0018: stloc.3
IL_0019: ldloc.3

代码语言:javascript
复制
// if (temp) // go to else branch
IL_001a: brtrue.s IL_0026
票数 1
EN

Stack Overflow用户

发布于 2015-03-10 21:14:39

编译器没有反转任何东西。请注意,if语句的两个分支在IL中的顺序与它们在源代码中的顺序相同。您可以从两个字符串的顺序中看出这一点。

当布尔值为false时,brtrue的使用只是用于分支的自然IL。测试布尔值是否为真意味着将其与0进行比较。值为0为false,其他值均为true。

因此,编译器发出IL来与0进行比较。如果比较为真,即如果布尔值具有序数值0,则布尔值为假。所以,如果分支等于零,就意味着分支,如果布尔值为false。这是对0的ceq,然后是brtrue

也就是说,值得指出的是,编译调试性能并不是问题。编译器想要编写代码,以便调试器可以检查变量。如果您对性能感兴趣,那么您必须查看发布版本中的IL。当你这样做的时候,你会看到完全不同的代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28964329

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档