为什么C#编译器把这种比较=就好像它是一个&GT!;比较呢? [英] Why does the C# compiler translate this != comparison as if it were a > comparison?

查看:265
本文介绍了为什么C#编译器把这种比较=就好像它是一个&GT!;比较呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有纯粹的偶然发现,C#编译器开启此方法:

I have by pure chance discovered that the C# compiler turns this method:

static bool IsNotNull(object obj)
{
    return obj != null;
}



...这个的 CIL

.method private hidebysig static bool IsNotNull(object obj) cil managed
{
    ldarg.0   // obj
    ldnull
    cgt.un
    ret
}

...或者,如果你喜欢看反编译的C#代码:

…or, if you prefer looking at decompiled C# code:

static bool IsNotNull(object obj)
{
    return obj > null;   // (note: this is not a valid C# expression)
}



怎么来的在 = 被翻译成> !?

推荐答案

有在IL没有比较 - 不等于指令,所以C#!= 经营者有没有确切的对应关系,不能直译。

Short answer:

There is no "compare-not-equal" instruction in IL, so the C# != operator has no exact correspondence and cannot be translated literally.

有不过是一个比较平等指令( CEQ ,直接对应到 == 运营商),因此在一般情况下,到X!= Y 被翻译像它稍长相当于(X == Y)==虚假

There is however a "compare-equal" instruction (ceq, a direct correspondence to the == operator), so in the general case, x != y gets translated like its slightly longer equivalent (x == y) == false.

有是的的一个比较-大于指令IL( CGT ),这使编译器可以采取一定的快捷方式(即产生较短的IL代码),一个是对空对象,的obj!= NULL ,得到好像他们是翻译的不平等比较 OBJ>空

There is also a "compare-greater-than" instruction in IL (cgt) which allows the compiler to take certain shortcuts (i.e. generate shorter IL code), one being that inequality comparisons of objects against null, obj != null, get translated as if they were "obj > null".

如果没有在IL没有比较 - 不等于指令,那么如何将下面的方法得到由编译器编译?

If there is no "compare-not-equal" instruction in IL, then how will the following method get translated by the compiler?

static bool IsNotEqual(int x, int y)
{
    return x != y;
}



正如上面已经说过,编译器将打开 !X = Y (X == Y)==虚假

.method private hidebysig static bool IsNotEqual(int32 x, int32 y) cil managed 
{
    ldarg.0   // x
    ldarg.1   // y
    ceq
    ldc.i4.0  // false
    ceq       // (note: two comparisons in total)
    ret
}

原来,编译器不会总是产生这个相当冗长的格局。让我们看看,当我们更换与常数0会发生什么:

It turns out that the compiler does not always produce this fairly long-winded pattern. Let's see what happens when we replace y with the constant 0:

static bool IsNotZero(int x)
{
    return x != 0;
}



中IL产生比在一般情况下稍短

The IL produced is somewhat shorter than in the general case:

.method private hidebysig static bool IsNotZero(int32 x) cil managed 
{
    ldarg.0    // x
    ldc.i4.0   // 0
    cgt.un     // (note: just one comparison)
    ret
}

编译器可以利用这一符号整数存储在的(其中,如果生成的位模式被解释为无符号整数—这是什么 .UN 表示— 0具有最小的可能值) ,所以它转换 X == 0 ,好像它是选中((UINT)x)> 0

The compiler can take advantage of the fact that signed integers are stored in two's complement (where, if the resulting bit patterns are interpreted as unsigned integers — that's what the .un means — 0 has the smallest possible value), so it translates x == 0 as if it were unchecked((uint)x) > 0.

原来,编译器可以对

static bool IsNotNull(object obj)
{
    return obj != null;
}



编译器生成几乎相同的IL为 IsNotZero

.method private hidebysig static bool IsNotNull(object obj) cil managed 
{
    ldarg.0
    ldnull   // (note: this is the only difference)
    cgt.un
    ret
}

显然,编译器允许假设引用的位模式是任何对象引用最小的比特模式成为可能。

Apparently, the compiler is allowed to assume that the bit pattern of the null reference is the smallest bit pattern possible for any object reference.

此快捷方式中显式的通用语言基础结构批注的标准(从10 2003年第1版)(491页,如表6-4的脚注,关于二进制比较或分公司业务部):

This shortcut is explicitly mentioned in the Common Language Infrastructure Annotated Standard (1st edition from Oct 2003) (on page 491, as a footnote of Table 6-4, "Binary Comparisons or Branch Operations"):

cgt.un 是允许的,可核查的ObjectRefs(O),这比较时,通常使用用空的ObjectRef(没有比较 - 不等于指令,这本来是一个比较明显的解决方案)。

"cgt.un is allowed and verifiable on ObjectRefs (O). This is commonly used when comparing an ObjectRef with null (there is no "compare-not-equal" instruction, which would otherwise be a more obvious solution)."

这篇关于为什么C#编译器把这种比较=就好像它是一个&GT!;比较呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆