短い答え:
ILには「compare-not-equal」命令!=
がないため、C#演算子には正確な対応がなく、文字どおりに変換できません。
ただし、「等しい」命令(ceq
、==
演算子への直接の対応)があるため、一般的にx != y
は、少し長い同等のように変換され(x == y) == false
ます。
ありも「比較-大なり」IL(の命令cgt
)コンパイラはヌルに対するオブジェクトの不平等の比較である、(すなわち短いILコードを生成する)1を特定のショートカットを取ることができ、obj != null
彼らがいたかのように、「変換されますobj > null
」
もう少し詳しく見てみましょう。
ILに「compare-not-equal」命令がない場合、コンパイラは次のメソッドをどのように変換しますか?
static bool IsNotEqual(int x, int y)
{
return x != y;
}
上ですでに述べたように、コンパイラーはをにx != 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
}
コンパイラは、このかなり長い時間のパターンを常に生成するとは限らないことがわかりました。y
定数0に置き換えるとどうなるか見てみましょう。
static bool IsNotZero(int x)
{
return x != 0;
}
生成されるILは、一般的な場合よりもやや短くなります。
.method private hidebysig static bool IsNotZero(int32 x) cil managed
{
ldarg.0 // x
ldc.i4.0 // 0
cgt.un // (note: just one comparison)
ret
}
コンパイラは、符号付き整数の中に格納されているという事実を利用することができ、2の補数( -何結果のビットパターンは符号なし整数として解釈されている場合、.un
それは変換して、0可能な最小値を有する-手段)はx == 0
、それがあたかもunchecked((uint)x) > 0
。
コンパイラーが不等式チェックに対しても同じようにできることがわかりましたnull
:
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
}
どうやら、コンパイラーは、null
参照のビットパターンがオブジェクト参照で可能な最小のビットパターンであると想定することを許可されています。
このショートカットは、共通言語インフラストラクチャアノテーション標準(2003年10月の第1版)(491ページ)で、表6-4「バイナリ比較またはブランチ演算」の脚注として明示的に言及されています。
" cgt.un
はObjectRefs(O)で許可および検証可能です。これは、ObjectRefをnullと比較するときに一般的に使用されます(" compare-not-equal "命令はありません。
int
は、の範囲内の負でない値がと同じように表現さint
れることだけですuint
。これは、2の補数よりもはるかに弱い要件です。