考虑这样一个循环:
for (int i = 0; i < end; ++i)
// do something
如果我知道 i 不会溢出,但我想在“做某事”部分检查溢出、截断等,我是否最好使用 checked
block 在循环内部还是外部?
for (int i = 0; i < end; ++i)
checked {
// do something
}
或
checked {
for (int i = 0; i < end; ++i)
// do something
}
更一般地说,在已检查和未检查模式之间切换是否有成本?
最佳答案
如果您真的想看到区别,请检查一些生成的 IL。让我们举一个非常简单的例子:
using System;
public class Program
{
public static void Main()
{
for(int i = 0; i < 10; i++)
{
var b = int.MaxValue + i;
}
}
}
我们得到:
.maxstack 2
.locals init (int32 V_0,
int32 V_1,
bool V_2)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0013
IL_0005: nop
IL_0006: ldc.i4 0x7fffffff
IL_000b: ldloc.0
IL_000c: add
IL_000d: stloc.1
IL_000e: nop
IL_000f: ldloc.0
IL_0010: ldc.i4.1
IL_0011: add
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: ldc.i4.s 10
IL_0016: clt
IL_0018: stloc.2
IL_0019: ldloc.2
IL_001a: brtrue.s IL_0005
IL_001c: ret
现在,让我们确认一下:
public class Program
{
public static void Main()
{
for(int i = 0; i < 10; i++)
{
checked
{
var b = int.MaxValue + i;
}
}
}
}
现在我们得到以下 IL:
.maxstack 2
.locals init (int32 V_0,
int32 V_1,
bool V_2)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0015
IL_0005: nop
IL_0006: nop
IL_0007: ldc.i4 0x7fffffff
IL_000c: ldloc.0
IL_000d: add.ovf
IL_000e: stloc.1
IL_000f: nop
IL_0010: nop
IL_0011: ldloc.0
IL_0012: ldc.i4.1
IL_0013: add
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldc.i4.s 10
IL_0018: clt
IL_001a: stloc.2
IL_001b: ldloc.2
IL_001c: brtrue.s IL_0005
IL_001e: ret
如您所见,唯一的区别(一些额外的 nop
除外)是我们的添加操作发出 add.ovf
而不是简单的 添加
。您将产生的唯一开销是这些操作的区别。
现在,如果我们移动 checked
block 以包含整个 for
循环会发生什么:
public class Program
{
public static void Main()
{
checked
{
for(int i = 0; i < 10; i++)
{
var b = int.MaxValue + i;
}
}
}
}
我们得到了新的 IL:
.maxstack 2
.locals init (int32 V_0,
int32 V_1,
bool V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldc.i4.0
IL_0003: stloc.0
IL_0004: br.s IL_0014
IL_0006: nop
IL_0007: ldc.i4 0x7fffffff
IL_000c: ldloc.0
IL_000d: add.ovf
IL_000e: stloc.1
IL_000f: nop
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add.ovf
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldc.i4.s 10
IL_0017: clt
IL_0019: stloc.2
IL_001a: ldloc.2
IL_001b: brtrue.s IL_0006
IL_001d: nop
IL_001e: ret
您可以看到两个 add
操作都已转换为 add.ovf
而不仅仅是内部操作,因此您获得了两倍的“开销”。无论如何,我猜测对于大多数用例来说,“开销”可以忽略不计。
关于c# - 进入和退出 C# 检查 block 是否有成本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32636110/