“ 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
首先进行隐式转换为double,其次不进行任何转换。
Serkan Arslan,

2
您的问题标题与正文中的问题不匹配,并且两个问题的答案不同。
埃里克·利珀特

1
@Eric Lippert实际上,问题的正文已由其他用户编辑。
srnldai

1
@Brian:不,原始海报是正确的;编辑更改了问题的含义,我没有注意到。我最初的问题是“有区别吗……?此外,有区别吗……?”。删除的“其他”表示原始张贴者意识到他们在问两个可能有不同答案的问题。这是一个坏习惯;理想情况下,问题应该问一个问题。但是,编辑使这两个问题看起来像是同一问题,而不是两个不同的问题。
埃里克·利珀特

Answers:


18

这里有两个问题,需要注意的是,他们有不同的答案。

有没有之间的差异double val = 1;double val = 1D;

否。C#编译器可以识别在预期为double的上下文中何时使用整数文字,并且在编译时进行类型更改,因此这两个片段将生成相同的代码。

以下两段代码之间有区别吗?

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

是。将整数常量自动更改为double的规则仅适用于常量,而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#编译器有时确实将用于提升算术的转换转移到条件主体中;我大约八年前编写了该代码,但是我不记得所有的细节。


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转换为double。

但是:(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 !! /!\
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.