zoukankan      html  css  js  c++  java
  • Why does the C# compiler translate this != comparison as if it were a > comparison?

    Question:

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

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

    …into this IL:

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

    …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)
    }

    How come that the != gets translated as a ">"?


    Answer:

    Short answer:

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

    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.

    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".


    Let's go into some more detail.

    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;
    }

    As already said above, the compiler will turn the x != y into (x == y) == false:

    .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
    }

    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;
    }

    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
    }

    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.

    It turns out the compiler can do just the same for inequality checks against null:

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

    The compiler produces almost the same IL as for 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.

    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 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)."



    想要看到更多学习笔记、考试复习资料、面试准备资料? 想要看到IBM工作时期的技术积累和国外初创公司的经验总结? 敬请关注: [CSDN](https://blog.csdn.net/u013152895) [简书](https://www.jianshu.com/u/594a3de3852d) [博客园](https://www.cnblogs.com/vigorz/) [51Testing](http://www.51testing.com/?15263728)
  • 相关阅读:
    图像边界扩展
    数据增强之图像旋转及坐标对应(附代码)
    Opencv中的阈值函数
    linux下C++遍历文件夹下的全部文件;Windows/Linux下C++批量修改文件名,批量删除文件
    提取内环图像
    linux中tab键不能补全,却能切换窗口
    Mathtype部分数学符号不能显示,只能显示方框时的解决办法
    Qt运行不出现界面
    直方图处理
    DTCMS自定义标签:面包屑导航,栏目中通过栏目调用名称获得栏目名称
  • 原文地址:https://www.cnblogs.com/vigorz/p/10499219.html
Copyright © 2011-2022 走看看