将long值与int / long零常量进行比较

时间:2013-03-31 15:09:14

标签: c# optimization

这是:

if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip

等于:

if (myLongValue > 0L)

这是使用特殊操作码吗? (类似于JZ - 如果在x86 asm中为零则跳转)。

2 个答案:

答案 0 :(得分:4)

2在IL方面完全相同。我们以下面的代码片段为例:

public static void Main(string[] args)
{
    long myLongValue = long.Parse("123");
    if (myLongValue > 0)
    {
        Console.WriteLine("ok");
    }
}

它被编译为以下IL(在发布模式下):

.method public hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int64 myLongValue)
    L_0000: ldstr "123"
    L_0005: call int64 [mscorlib]System.Int64::Parse(string)
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldc.i4.0 
    L_000d: conv.i8 
    L_000e: ble.s L_001a
    L_0010: ldstr "ok"
    L_0015: call void [mscorlib]System.Console::WriteLine(string)
    L_001a: ret 
}

现在将if (myLongValue > 0)替换为if (myLongValue > 0L),您将获得严格等效的IL。

更优化的IL会是这样但不幸的是我无法使编译器发出它:

.method public hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int64 myLongValue)
    L_0000: ldstr "123"
    L_0005: call int64 [mscorlib]System.Int64::Parse(string)
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldc.i8.0 
    L_000d: ble.s L_001a
    L_0010: ldstr "ok"
    L_0015: call void [mscorlib]System.Console::WriteLine(string)
    L_001a: ret 
}

这里我们不需要conv.i8指令,因为我们已经将Int64类型的提供值直接推送到评估堆栈中作为int64。

答案 1 :(得分:1)

在您的第一个示例中,运算符>的左侧是longSystem.Int64),右侧是int({ {1}})。由于C#规范没有使用该签名定义System.Int32运算符的重载,因此我们必须检查某些转换是否适用于一个(或两个)参数(操作数)。 / p>

存在从>int隐式转换。另一个方向的转换不是隐含的。因此,右侧通过扩展转换进行转换,并使用重载long

因为在这种情况下,右侧operator >(long x, long y)是编译时文字,编译器可以扩展常量,所以你的两个没有区别编译后的例子。另一个答案已经证明了IL的输出结果。

那么如果你有了:

int

通常,从ulong myULongValue = XXX; if (myULongValue > 0) ... (已签名)到int(无符号),没有隐式转换。但是,当ulong是编译时常量(文字)恰好是非负数时,确实存在转换。所以我上面的例子仍然有效(并产生与int相同的内容。)

但对于非常数if (myULongValue > 0ul),它必须失败:

int