比较long value与int/long零常量

本文关键字:long 常量 value 比较 int | 更新日期: 2023-09-27 18:06:47

这是:

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

等于:

if (myLongValue > 0L)

是否使用了特殊的操作码?(类似于x86 asm中的JZ - jump if 0)。

比较long value与int/long零常量

两者在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 > 0L)代替if (myLongValue > 0),得到严格等价的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压入计算堆栈。

在您的第一个示例中,操作符>的左侧是long (System.Int64),右侧是int (System.Int32)。由于c#规范没有定义带有该签名的>操作符的重载,因此必须检查是否对其中一个(或两个)实参(操作数)进行了转换。

存在一个隐式的从intlong转换。另一个方向的转换并不是隐含的。因此,右侧通过一个加宽转换进行转换,并使用了重载operator >(long x, long y)

由于在这种情况下,右边的int是编译时字量,编译器可以对常量进行扩展,因此编译后两个示例之间没有区别。另一个答案已经演示了输出IL的样子。

如果你用:

ulong myULongValue = XXX;
if (myULongValue > 0)
    ...
一般来说,没有从int(有符号)到ulong(无符号)的隐式转换。但是,当int是一个编译时常量(字面量)并且恰好是非负的时候,确实存在转换。所以我上面的例子仍然有效(并且产生与if (myULongValue > 0ul)相同的结果)。

但是对于非常数int,它必须失败:

ulong myULongValue = XXX;
int zero = 0;               // not const
if (myULongValue > zero)    // will NOT compile!
    ...