c# - 进入和退出 C# 检查 block 是否有成本?

标签 c# integer-arithmetic

考虑这样一个循环:

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/

相关文章:

c - C代码中忽略的模数操作数

perl 整数算术给出浮点答案

c++ - 无符号算术和整数溢出

c# - 将 List<double> 转换为 C# 中的 DataTable 列

c# - 比较使用 Thread.Sleep 和 Timer 延迟执行

c# - 在 PostgreSQL 中存储基于 NodaTime 的值的最佳方法是什么?

c# - 包含引用后无法使用项目中的命名空间? F# C#

java - 圆长从 1004L 到 1000L(或 1006L 到 1010L)

c# - 关于 Facebook SDK 的问题。 Facebook 图片 URL 每次登录都会更改吗?如何在 Unity C# 中从 Facebook SDK 7.9 获取图像 URL 和 Facebook ID?

python - 为什么 2 * x * x 在 Python 3.x 中比 2 * ( x * x ) 快,对于整数?