[C#] 왜 C # 컴파일러가이 비교를 마치> 비교 인 것처럼 해석합니까?

나는 우연히 C # 컴파일러 가이 방법을 돌리는 것을 발견했다.

static bool IsNotNull(object obj)
{
    return obj != null;
}

…이 CIL에 :

.method private hidebysig static bool IsNotNull(object obj) cil managed
{
    ldarg.0   // obj
    ldnull
    cgt.un
    ret
}

또는 디 컴파일 된 C # 코드를 선호하는 경우 :

static bool IsNotNull(object obj)
{
    return obj > null;   // (note: this is not a valid C# expression)
}

!=>” 로 번역 된 결과는 어떻게 됩니까?



답변

짧은 답변:

IL에는 “같지 않은 비교”명령 !=이 없으므로 C # 연산자는 정확히 일치하지 않으며 문자 그대로 번역 할 수 없습니다.

그러나 “비교-동일”명령 ( 연산자 ceq와 직접 대응 ==)이 있으므로 일반적으로 x != y약간 더 긴 것으로 번역 (x == y) == false됩니다.

또한 는 “비교 -보다 큼”IL (의 명령 cgt) 컴파일러가 널 (null)에 대한 객체의 불평등 비교되는 (즉, 짧은 IL 코드를 생성)를 특정 단축키를 활용할 수 있습니다, obj != null그들은 것처럼, “번역 취득 obj > null“.

좀 더 자세히 살펴 보겠습니다.

IL에 “같지 않은 비교”명령이 없으면 컴파일러가 다음 방법을 어떻게 변환합니까?

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과 비교할 때 일반적으로 사용됩니다 (“같지 않은 비교 “명령이없는 경우가 더 분명합니다).”


답변