มีความแตกต่างระหว่าง“ double val = 1;” หรือไม่ และ“ double val = 1D;” หรือไม่


17

มีความแตกต่างระหว่างโค้ดสองชิ้นต่อไปนี้หรือไม่?

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

}

ฉันพบว่ารหัสฐานของเราใช้วิธีที่สองในการเขียน


จากด้านบนของหัวของฉันคนแรกเกี่ยวข้องกับโปรโมชั่นยาวถึงสองครั้ง
Tanveer Badar

2
ก่อนทำการแปลงโดยนัยเป็นสองเท่าและที่สองไม่ทำการแปลงใด ๆ
Serkan Arslan

2
ชื่อคำถามของคุณและคำถามในเนื้อหาไม่ตรงกันและคำถามสองข้อนั้นมีคำตอบที่แตกต่างกัน
Eric Lippert

1
@Eric Lippert ที่จริงแล้วเนื้อความของคำถามได้รับการแก้ไขโดยผู้ใช้รายอื่น
srnldai

1
@Brian: ไม่โปสเตอร์ต้นฉบับถูกต้อง การแก้ไขเปลี่ยนความหมายของคำถามซึ่งฉันไม่ได้สังเกต คำถามเดิมคือ "มีความแตกต่าง ... หรือไม่นอกจากนี้มีความแตกต่าง ... ?" เน้นของฉัน "เพิ่มเติม" ที่ลบออกแสดงว่าผู้โพสต์ดั้งเดิมตระหนักว่าพวกเขากำลังถามคำถามสองข้อที่อาจมีคำตอบที่แตกต่างกัน นั่นเป็นวิธีปฏิบัติที่ไม่ดี คำถามควรนึกคิดคำถามเดียว แต่การแก้ไขทำให้ดูเหมือนว่าคำถามสองข้อนั้นมีจุดประสงค์ที่จะเป็นคำถามเดียวกันไม่ใช่คำถามที่แตกต่างกันสองข้อ
Eric Lippert

คำตอบ:


18

มีสองคำถามที่นี่และเป็นสิ่งสำคัญที่จะต้องทราบว่าพวกเขามีคำตอบที่แตกต่างกัน

มีความแตกต่างระหว่างdouble val = 1;และdouble val = 1D;?

ไม่คอมไพเลอร์ C # รับรู้เมื่อมีการใช้ตัวอักษรจำนวนเต็มในบริบทที่คาดว่าจะเป็นสองเท่าและประเภทการเปลี่ยนแปลงในเวลารวบรวมดังนั้นสองชิ้นนี้จะสร้างรหัสเดียวกัน

มีความแตกต่างระหว่างโค้ดสองชิ้นต่อไปนี้หรือไม่?

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;

นั่นคือในครั้งแรกที่เราเลือกจำนวนเต็มแล้วแปลงเป็นสองเท่าและในวินาทีที่เราเลือกคู่

FYI: คอมไพเลอร์ C # หรือตัวกระวนกระวายใจได้รับอนุญาตให้รับรู้ว่าโปรแกรมแรกสามารถเพิ่มประสิทธิภาพเป็นครั้งที่สองได้ แต่ฉันไม่รู้ว่ามันจริงหรือไม่ คอมไพเลอร์ C # บางครั้งจะย้ายการแปลงสำหรับการยกค่าทางคณิตศาสตร์ลงในเนื้อความของเงื่อนไข ฉันเขียนโค้ดนั้นเมื่อแปดปีที่แล้วตอนนี้ แต่ฉันจำรายละเอียดทั้งหมดไม่ได้


6

มีคือความแตกต่างในรหัส 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 เป็นสองเท่า

อย่างไรก็ตาม: (1) ผลลัพธ์สุดท้ายนั้นเหมือนกันและ (2) คอมไพเลอร์ JIT อาจแปลทั้งสองอย่างนี้เป็นรหัสเครื่องเดียวกันได้

ดังนั้นคำตอบคือใช่มีคือความแตกต่าง - แต่ไม่ว่าคุณจะต้องกังวลเกี่ยวกับ

โดยส่วนตัวฉันจะไปหาเวอร์ชั่นที่สองเพราะนั่นเป็นการแสดงเจตนาของโปรแกรมเมอร์ได้ดีขึ้นและอาจสร้างโค้ดที่มีประสิทธิภาพมากขึ้นเล็กน้อย (ขึ้นอยู่กับสิ่งที่คอมไพเลอร์ JIT ใช้)


4

ไม่มีความแตกต่างคอมไพเลอร์ฉลาดพอที่จะทำการแปลงโดยปริยายหรือไม่
อย่างไรก็ตามถ้าคุณใช้varคุณต้องเขียนvar val = 42D;เพื่อให้แน่ใจว่าตัวแปรนั้นเป็น double และไม่ใช่ 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 !! /!\
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.