Câu trả lời ngắn:
Không có hướng dẫn "so sánh không bằng" trong IL, vì vậy !=
toán tử C # không có sự tương ứng chính xác và không thể được dịch theo nghĩa đen.
Tuy nhiên, có một lệnh "so sánh bằng" ( ceq
, tương ứng trực tiếp với ==
toán tử), vì vậy trong trường hợp chung, x != y
được dịch giống như tương đương dài hơn một chút (x == y) == false
.
Ngoài ra còn có một lệnh "so sánh lớn hơn" trong IL ( cgt
) cho phép trình biên dịch thực hiện một số phím tắt nhất định (nghĩa là tạo mã IL ngắn hơn), một trong số đó là so sánh bất bình đẳng của các đối tượng với null obj != null
, được dịch như thể chúng là " obj > null
".
Chúng ta hãy đi vào chi tiết hơn.
Nếu không có lệnh "so sánh không bằng" trong IL, thì phương thức sau đây sẽ được dịch bởi trình biên dịch như thế nào?
static bool IsNotEqual(int x, int y)
{
return x != y;
}
Như đã nói ở trên, trình biên dịch sẽ biến x != y
thành (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
}
Nó chỉ ra rằng trình biên dịch không phải lúc nào cũng tạo ra mô hình khá dài này. Hãy xem điều gì xảy ra khi chúng ta thay thế y
bằng hằng số 0:
static bool IsNotZero(int x)
{
return x != 0;
}
IL được sản xuất có phần ngắn hơn so với trường hợp chung:
.method private hidebysig static bool IsNotZero(int32 x) cil managed
{
ldarg.0 // x
ldc.i4.0 // 0
cgt.un // (note: just one comparison)
ret
}
Trình biên dịch có thể lợi dụng thực tế là các số nguyên đã ký được lưu trữ trong phần bù hai (trong đó, nếu các mẫu bit kết quả được hiểu là các số nguyên không dấu - đó là những gì .un
có nghĩa là - 0 có giá trị nhỏ nhất có thể), vì vậy nó dịch x == 0
như thể nó là unchecked((uint)x) > 0
.
Hóa ra trình biên dịch có thể làm tương tự đối với kiểm tra bất đẳng thức đối với null
:
static bool IsNotNull(object obj)
{
return obj != null;
}
Trình biên dịch tạo ra gần như cùng IL với IsNotZero
:
.method private hidebysig static bool IsNotNull(object obj) cil managed
{
ldarg.0
ldnull // (note: this is the only difference)
cgt.un
ret
}
Rõ ràng, trình biên dịch được phép giả định rằng mẫu bit của null
tham chiếu là mẫu bit nhỏ nhất có thể cho bất kỳ tham chiếu đối tượng nào.
Phím tắt này được đề cập rõ ràng trong Tiêu chuẩn cơ sở hạ tầng ngôn ngữ chung (phiên bản 1 từ tháng 10 năm 2003) (trên trang 491, như một chú thích của Bảng 6-4, "So sánh nhị phân hoặc Hoạt động chi nhánh"):
" cgt.un
được cho phép và có thể kiểm chứng trên ObjectRefs (O). Điều này thường được sử dụng khi so sánh ObjectRef với null (không có hướng dẫn" so sánh không bằng ", nếu không sẽ là một giải pháp rõ ràng hơn)."
int
phạm vi có cùng biểu diễnint
giống như khi chúng thực hiệnuint
. Đó là một yêu cầu yếu hơn nhiều so với bổ sung của hai.