Jawaban singkat:
Tidak ada instruksi "bandingkan-tidak-sama" dalam IL, sehingga !=
operator C # tidak memiliki korespondensi yang tepat dan tidak dapat diterjemahkan secara harfiah.
Namun ada instruksi "bandingkan-sama" ( ceq
, korespondensi langsung ke ==
operator), jadi dalam kasus umum, x != y
diterjemahkan seperti padanan yang sedikit lebih panjang (x == y) == false
.
Ada juga instruksi "bandingkan-lebih-dari-dalam" di IL ( cgt
) yang memungkinkan kompiler mengambil jalan pintas tertentu (yaitu menghasilkan kode IL lebih pendek), salah satunya adalah bahwa perbandingan ketidaksetaraan objek terhadap nol,, obj != null
diterjemahkan seolah-olah mereka " obj > null
".
Mari kita bahas lebih detail.
Jika tidak ada instruksi "bandingkan-tidak-sama" dalam IL, lalu bagaimana metode berikut akan diterjemahkan oleh kompiler?
static bool IsNotEqual(int x, int y)
{
return x != y;
}
Seperti yang sudah dikatakan di atas, kompiler akan mengubahnya x != y
menjadi (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
}
Ternyata kompiler tidak selalu menghasilkan pola yang bertele-tele. Mari kita lihat apa yang terjadi ketika kita mengganti y
dengan konstanta 0:
static bool IsNotZero(int x)
{
return x != 0;
}
IL yang diproduksi agak lebih pendek daripada dalam kasus umum:
.method private hidebysig static bool IsNotZero(int32 x) cil managed
{
ldarg.0 // x
ldc.i4.0 // 0
cgt.un // (note: just one comparison)
ret
}
Kompilator dapat mengambil keuntungan dari fakta bahwa bilangan bulat yang ditandatangani disimpan dalam komplemen dua (di mana, jika pola bit yang dihasilkan ditafsirkan sebagai bilangan bulat yang tidak ditandatangani - itulah .un
artinya - 0 memiliki nilai sekecil mungkin), sehingga menerjemahkan x == 0
seolah-olah itu adalah unchecked((uint)x) > 0
.
Ternyata kompiler dapat melakukan hal yang sama untuk pemeriksaan ketimpangan terhadap null
:
static bool IsNotNull(object obj)
{
return obj != null;
}
Kompiler menghasilkan IL yang hampir sama dengan untuk IsNotZero
:
.method private hidebysig static bool IsNotNull(object obj) cil managed
{
ldarg.0
ldnull // (note: this is the only difference)
cgt.un
ret
}
Rupanya, kompiler diperbolehkan untuk mengasumsikan bahwa pola bit dari null
referensi adalah pola bit terkecil yang mungkin untuk referensi objek apa pun.
Pintasan ini secara eksplisit disebutkan dalam Common Language Infrastructure Annotated Standard (edisi pertama dari Oktober 2003) (di halaman 491, sebagai catatan kaki pada Tabel 6-4, "Perbandingan Biner atau Operasi Cabang"):
" cgt.un
diperbolehkan dan dapat diverifikasi pada ObjectRefs (O). Ini biasanya digunakan ketika membandingkan ObjectRef dengan nol (tidak ada instruksi" bandingkan-tidak-sama ", yang kalau tidak akan menjadi solusi yang lebih jelas)."
int
kisaran memiliki representasi yang samaint
seperti ketika mereka masukuint
. Itu persyaratan yang jauh lebih lemah daripada komplemen dua.