c# - C# 中算术溢出检查的最佳实践是什么?

标签 c# compiler-construction overflow keyword checked

网络/stackoverflow 上有一些关于“checked”关键字与编译器选项“Check for arithmetic overflow/underflow”用法的好文章,例如:

http://www.codethinked.com/c-trivia-what-no-overflow

Why doesn't C# use arithmetic overflow checking by default?

Best way to handle Integer overflow in C#?

我仍然不知道应该使用哪一个。默认情况下,我更愿意使用编译器选项以确保始终安全,不要让 unchecked 关键字使我的代码困惑,不要在某些地方忘记它,最后它不是很常用,所以很多开发人员可能不知道。

但是我所承受的实际性能损失有多严重?我想 MS 设置默认不进行溢出检查是有充分理由的。编译器选项是否只涉及我的代码或每个使用的库和框架本身?

最佳答案

我也有同样的疑问。我更喜欢在我公司的代码中默认检查一段代码,因为溢出副作用会花费很多并且难以诊断。发现这些副作用的真正原因非常有值(value)。

问题是,我们在性能方面损失了什么?

这是一个非常简单的工作台:

static void Main(string[] args)
{
    long c = 0;
    var sw = new Stopwatch();
    sw.Start();
    unchecked
    {
        for (long i = 0; i < 500000000; i++) c += 1;
    }
    sw.Stop();
    Console.WriteLine("Unchecked: " + sw.ElapsedMilliseconds);

    c = 0;
    sw.Restart();
    checked
    {
        for (long i = 0; i < 500000000; i++) c += 1;
    }
    sw.Stop();
    Console.WriteLine("Checked: " + sw.ElapsedMilliseconds);
}

在生成的 IL 中,我看到 checkedunchecked 关键字决定了 add.ovf 还是 add 指令。 (用于调试和发布配置)

IL_001c:  ldloc.2
IL_001d:  ldc.i4.1
IL_001e:  conv.i8
IL_001f:  add


IL_0066:  ldloc.2
IL_0067:  ldc.i4.1
IL_0068:  conv.i8
IL_0069:  add.ovf

结果(x64 主机)

调试

  • 未选中:2371
  • 检查:2437

发布

  • 未选中:2088
  • 检查:2266

用 int(s) 替换 long(s) 的其他结果(x64 主机)

调试

  • 未选中:1665
  • 检查:1568

发布

  • 未选中:189
  • 已检查:566

性能受到影响,看起来选择正确的变量类型比选中或不选中更重要。无论如何,这不会改变我的看法。我将在我们所有的项目中打开“检查算术溢出/下溢”! (高级build设置)。

当需要性能时,我会简单地使用一个unchecked block 。

关于c# - C# 中算术溢出检查的最佳实践是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19225535/

相关文章:

c - 整数溢出漏洞

c# - 删除其中一条后对剩余记录重新编号

compiler-construction - Turbo Pascal 3.01A Turboh错误: “co processor card not responding”

c++ - 返回对象存储在哪里?

c - 未定义引用?但我已经实现了这个功能

css - 如何在网站宽度之外设置带有图像的div,不显示滚动条?

html - 获取 Div 背景图片到 "overflow"往上

c# - 维西.CoolStorage : filter with ManyToOne and ManyToMany relation

c# - 相当于c#中的Point和Size

c# - 在 ASP.NET RegularExpressionValidator 中忽略区分大小写