为什么C#编译器把这种比较=就好像它是一个>!;比较呢? [英] Why does the C# compiler translate this != comparison as if it were a > comparison?
问题描述
我有纯粹的偶然发现,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
.
原来,编译器可以对空$ C $不平等检查做一样的!C>:
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#编译器把这种比较=就好像它是一个>!;比较呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!