다음 두 코드 조각간에 차이점이 있습니까?
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.r8
int를 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 !! /!\