Why does the C# compiler translate this != comparison as if it were a > comparison?
2015-03-24 15:50
127 查看
Question:
I have by pure chance discovered that the C# compiler turns this method:
…into this IL:
…or, if you prefer looking at decompiled C# code:
How come that the
translated as a "
Answer:
There is no "compare-not-equal" instruction in IL, so the C#
has no exact correspondence and cannot be translated literally.
There is however a "compare-equal" instruction (
a direct correspondence to the
so in the general case,
There is also a "compare-greater-than" instruction in IL (
which allows the compiler to take certain shortcuts (i.e. generate shorter IL code), one being that inequality comparisons of objects against null,
If there is no "compare-not-equal" instruction in IL, then how will the following method get translated by the compiler?
As already said above, the compiler will turn the
It turns out that the compiler does not always produce this fairly long-winded pattern. Let's see what happens when we replace
the constant 0:
The IL produced is somewhat shorter than in the general case:
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
— 0 has the smallest possible value), so it translates
It turns out the compiler can do just the same for inequality checks against
The compiler produces almost the same IL as for
Apparently, the compiler is allowed to assume that the bit pattern of the
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"):
"
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)."
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 != ygets 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 != yinto
(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
ywith
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
.unmeans
— 0 has the smallest possible value), so it translates
x == 0as 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
nullreference
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.unis
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)."
相关文章推荐
- Why does Windows not recognize my USB device as the same device if I plug it into a different port?
- [zz]Why does the compiler generate a MOV EDI, EDI instruction at the beginning of functions?
- the file will be lost if save this file as ansi encoded text file
- 【MySQL案例】error.log的Warning:If a crash happens thisconfiguration does not guarantee that the relay lo
- Why does the compiler generate a MOV EDI, EDI instruction at the beginning of functions?
- Windows ->> FIX: “The security database on the server does not have a computer account for this workstation trust relationship”
- Why does Quora use MySQL as the data store instead of NoSQLs such as Cassandra, MongoDB, CouchDB etc?
- TextView with SingleLine as true and Gravity as Center not passing the events to the ViewPager if it has a Click Event
- xcode 弹出的错误 1 <Xcode cannot launch apps on the simulated device “iPhone 5s”, as it is cur>
- A class file was not written. The project may be inconsistent, if so try refreshing this project and building it. eclipse提示错误
- Cannot execute as the database principal because the principal "guest" does not exist, this type of principal cannot be impersonated, or you do not have permission.
- How to scroll an image, if it does not fit in the display
- Use C# to get JSON Data from the Web and Map it to .NET Class => Made Easy! 转
- I Will Live This Day as if It Is My Last
- 【MySQL案例】error.log的Warning:If a crash happens thisconfiguration does not guarantee that the relay lo(转)
- Why c++ has friend members while C# does not have this?
- A class file was not written. The project may be inconsistent, if so try refreshing this project and building it
- A class file was not written. The project may be inconsistent, if so try refreshing this project and building it. eclipse提示错误
- Write Code as If You Had to Support It for the Rest of Your Life
- Judging whether object existed in the database, if it does, delete it.