IT story

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

hot-time 2020. 6. 14. 09:52
반응형

왜 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
}

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 == 0 as if it were unchecked((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.un is 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)."

참고URL : https://stackoverflow.com/questions/28781839/why-does-the-c-sharp-compiler-translate-this-comparison-as-if-it-were-a-com

반응형