[c#] “double val = 1;”의 차이점이 있습니까? 그리고 “double val = 1D;”?

다음 두 코드 조각간에 차이점이 있습니까?

class Test {

    public readonly double Val;

    public Test(bool src) {
        this.Val = src ? 1 : 0;
    }

}

class Test {

    public readonly double Val;

    public Test(bool src) {
        this.Val = src ? 1D : 0D;
    }

}

코드베이스가 두 번째 작성 방식을 사용한다는 것을 알았습니다.



답변

여기에는 두 가지 질문이 있으며 답변이 서로 다르다는 점에 유의하십시오.

double val = 1;와 사이에 차이가 double val = 1D;있습니까?

C # 컴파일러는 double이 예상되는 컨텍스트에서 정수 리터럴이 사용되는 시점을 인식하고 컴파일 타임에 유형이 변경되므로이 두 조각은 동일한 코드를 생성합니다.

다음 두 코드 조각간에 차이점이 있습니까?

double Val;
...
this.Val = src ? 1 : 0;
---
this.Val = src ? 1D : 0D;

예. 정수 상수가 자동으로 더블로 변경된다는 규칙은 적용 상수 , 그리고 src ? ...하지 않은 것입니다 상수 . 컴파일러는 작성한 것처럼 전자를 생성합니다.

int t;
if (src)
  t = 1;
else
  t = 0;
this.Val = (double)t;

그리고 두 번째

double t;
if (src)
  t = 1D;
else
  t = 0D;
this.Val = t;

즉, 첫 번째는 정수를 선택한 다음 두 배로 변환하고 두 번째는 두 배를 선택합니다.

참고 : C # 컴파일러 또는 지터가된다 허용 된 첫 번째 프로그램이 두 번째로 최적화 될 수 있다는 것을 인식하지만, 실제로 그렇게 나도 몰라. C # 컴파일러 때때로 해제에 대한 변환을 이동합니다. 산술에 조건부 본문으로 가 있습니다. 나는 약 8 년 전에 그 코드를 썼지 만 모든 세부 사항을 기억하지는 않습니다.


답변

거기 이다 생성 IL 코드의 차이.

이 수업 :

class Test1
{
    public readonly double Val;

    public Test1(bool src)
    {
        this.Val = src ? 1 : 0;
    }
}

생성자를 위해이 IL 코드를 생성합니다.

.class private auto ansi beforefieldinit Demo.Test1
    extends [mscorlib]System.Object
{
    .field public initonly float64 Val

    .method public hidebysig specialname rtspecialname instance void .ctor (
            bool src
        ) cil managed
    {
        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ldarg.0
        IL_0007: ldarg.1
        IL_0008: brtrue.s IL_000d

        IL_000a: ldc.i4.0
        IL_000b: br.s IL_000e

        IL_000d: ldc.i4.1

        IL_000e: conv.r8
        IL_000f: stfld float64 Demo.Test1::Val
        IL_0014: ret
    }
}

그리고이 수업은 :

class Test2
{
    public readonly double Val;

    public Test2(bool src)
    {
        this.Val = src ? 1d : 0d;
    }
}

생성자를 위해이 IL 코드를 생성합니다.

.class private auto ansi beforefieldinit Demo.Test2
    extends [mscorlib]System.Object
{
    .field public initonly float64 Val

    .method public hidebysig specialname rtspecialname instance void .ctor (
            bool src
        ) cil managed
    {
        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ldarg.0
        IL_0007: ldarg.1
        IL_0008: brtrue.s IL_0015

        IL_000a: ldc.r8 0.0
        IL_0013: br.s IL_001e

        IL_0015: ldc.r8 1

        IL_001e: stfld float64 Demo.Test2::Val
        IL_0023: ret
    }
}

보시다시피, 첫 번째 버전에서는 conv.r8int를 double로 변환하기 위해 호출 해야합니다.

그러나 (1) 최종 결과는 동일하며 (2) JIT 컴파일러는이 두 가지를 모두 동일한 기계 코드로 변환 할 수 있습니다.

대답은 그래서 : 네, 있습니다 -하지만 당신은 걱정할 필요가없는 하나의 차이.

개인적으로, 나는 프로그래머의 의도를 더 잘 표현 하고 JIT 컴파일러가 얻는 것에 따라 매우 약간 더 효율적인 코드를 생성 할 수 있기 때문에 두 번째 버전으로 갈 것입니다 .


답변

차이점은 없습니다. 컴파일러는 암시 적으로 변환을 수행 할 수있을만큼 똑똑합니다.
당신이 사용하는 경우 그러나 var, 당신이 작성해야 var val = 42D;할 것은 반드시 변수를 int 더블 및 아니다.

double foo = 1;  // This is a double having the value 1
double bar = 1d; // This is a double having the value 1

var val = 42d;   // This is a double having the value 42
var val2 = 42;   // /!\ This is an int having the value 42 !! /!\


답변