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 gets translated like its slightly longer equivalent
!= y(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, get translated as if they were "
!= nullobj".
> 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 into
!= y(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 as if it were
== 0unchecked((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.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 the C# compiler translate this != comparison as if it were a > comparison?的更多相关文章
- deque Comparison of Queue and Deque methods Comparison of Stack and Deque methods
1. 队列queue和双端队列deque的转换 Queue Method Equivalent Deque Methodadd(e) addLast(e)offer(e) offerLast(e)re ...
- .NET (四)委托第四讲:内置委托Comparison
// 摘要: // 表示比较同一类型的两个对象的方法. // // 参数: // x: // 要比较的第一个对象. // // y: // 要比较的第二个对象. // // 类型参数: // T: / ...
- EF 5 最佳实践白皮书
Performance Considerations for Entity Framework 5 By David Obando, Eric Dettinger and others Publish ...
- Intel graphics processing units
http://en.wikipedia.org/wiki/Comparison_of_Intel_graphics_processing_units Comparison of Intel graph ...
- Oracle Database 11g express edition
commands : show sys connect sys as sysdba or connect system as sysdba logout or disc clear screen or ...
- SAP ABAP 处理字符串串串串串串串串(详细)
关于ABAP中处理字符串的方法,非常详细,学习过程中总结一下分享给大家,,, ABAP/4 提供多个处理类型 C 即字符串 的数据对象的关键字. 处理字符串 的方法有: 1.拆分字符串split 2. ...
- RFC 2616
Network Working Group R. Fielding Request for Comments: 2616 UC Irvine Obsoletes: 2068 J. Gettys Cat ...
- 教程less
http://lesscss.cn/features/ Overview As an extension to CSS, Less is not only backwards compatible w ...
- 【转】Everything you need to know about NoSQL databases
原文: https://dev.to/lmolivera/everything-you-need-to-know-about-nosql-databases-3o3h ---------------- ...
随机推荐
- 【python-appium】手机一直提示重新安装settings unlock 输入法等 注释掉以下代码
注释掉目录:C:\Program Files (x86)\Appium\node_modules\appium\lib\devices\android\android.js this.initUnic ...
- 24.HashSet
在前篇博文(HashMap)中详细讲解了HashMap的实现过程,对于HashSet而言,它是基于HashMap来实现的,底层采用HashMap来保存元素.所以如果对HashMap比较熟悉,那么Has ...
- Android-Java-静态成员变量&成员变量&局部变量(内存图&回收机制)
静态成员变量(回收机制) StaticDemo 和 MyDemo package android.java.oop13; class MyDemo { /** * 定义一个静态变量 */ public ...
- C# 多线程 举例使用
使用多线程的几种方式 (1)不需要传递参数,也不需要返回参数 ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值. /// <summa ...
- MySQL性能调优与诊断
* 本篇随笔为<涂抹MySQL>一书的阅读摘抄,详细请查看正版书籍 关键性指标 IOPS(Input/Output operations Per Second) 每秒处理的I/O请求次数 ...
- Java中的Lock接口
Synchronized & Lock synchronized 是Java语言中的关键字,由monitorenter,monitorexit两个指令实现.JVM会将monitorenter指 ...
- LeetCode:114_Flatten Binary Tree to Linked List | 将一棵二叉树变成链表的形式 | Medium
要求:Given a binary tree, flatten it to a linked list in-place.将二叉树转化为平坦序列的树.比如: 结题思路: 该题有个提示,转化后的树的序列 ...
- 《JavaScript高级教程》学习笔记一、变量和数据类型
JavaScript的核心语言特性在ECMA-262中是以名为ECMAScript的伪语言的形式来定义的. 一.变量和数据类型 1. 变量 JavaSript是弱类型语言,可以通过var定义任何类型变 ...
- 京东架构师的showtime京东个性化推荐系统实战
推荐系统核心任务是排序,从线上服务角度看,就是将数据从给定集合中数据选择出来,选出后根据一定规则策略方法进行排序. 线上服务要根据一定规则进行架构设计,架构设计是什么?每一次权衡取舍都是设计,设计需要 ...
- Percona 数据库
1. Percona介绍 Percona Server由领先的MySQL咨询公司Percona发布. Percona Server是一款独立的数据库产品,其可以完全与MySQL兼容,可以在不更改代码的 ...