比较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)。
两者在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#规范没有定义带有该签名的>
操作符的重载,因此必须检查是否对其中一个(或两个)实参(操作数)进行了转换。
存在一个隐式的从int
到long
的转换。另一个方向的转换并不是隐含的。因此,右侧通过一个加宽转换进行转换,并使用了重载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!
...