64位-在没有调试的情况下启动的C#64位版本构建与在启动调试(BigInteger)时的行为不同

本文关键字:调试 启动 BigInteger 情况下 C#64 版本 64位 构建 | 更新日期: 2023-09-27 18:00:38

我是C#的新手,遇到了以下代码的问题(我的目标框架是4.5,我添加了对System.Numerics的引用):

using System;
using System.Numerics;
namespace Test
{
    class Program
    {
        static BigInteger Gcd(BigInteger x, BigInteger y)
        {
            Console.WriteLine("GCD {0}, {1}", x, y);
            if (x < y) return Gcd(y, x);
            if (x % y == 0) return y;
            return Gcd(y, x % y);
        }
        static void Main(string[] args)
        {
            BigInteger a = 13394673;
            BigInteger b = 53578691;
            Gcd(a, b);
        }
    }
}

当版本构建开始调试时(VisualStudio中的F5,以及程序末尾的一个断点,这样我就可以看到输出),我得到以下输出:

GCD 13394673, 53578691
GCD 53578691, 13394673
GCD 13394673, 13394672
GCD 13394672, 1

然而,当版本构建在没有调试的情况下启动时(Ctrl-F5),我会得到以下内容:

GCD 13394673, 53578691
GCD 53578691, 53578691

奇怪的是,如果我添加一个控制台。ReadLine()在程序结束时,它按预期工作!

你知道是什么原因造成的吗?谢谢

64位-在没有调试的情况下启动的C#64位版本构建与在启动调试(BigInteger)时的行为不同

这是中的x64抖动优化器错误。NET 4.0至4.5.2。描述它相当困难,由于BigInteger的使用,代码生成相当重。x64抖动有struct类型(如BigInteger)的优化器错误历史,因此这可能是根本原因。在这种方法中,与可能的尾部调用优化相结合是最有可能的触发因素。

我通常会建议报告这样的错误,但这种抖动的日子已经不多了。微软决定将其退役并彻底重写。中提供。NET 4.6-VS2015,项目代码名称为RyuJIT。它没有这个bug。

几种可能的解决方案:

Project+Properties,Build选项卡,Platform target=x86。这迫使程序在32位模式下运行,并使用x86抖动,它没有这个错误。

或者使用属性禁用此方法的优化:

  using System.Runtime.CompilerServices;
  ...
    [MethodImpl(MethodImplOptions.NoOptimization)]
    static BigInteger Gcd(BigInteger x, BigInteger y) {
        // etc...
    }

还好,繁重的工作在BigInteger类中,所以禁用优化不会影响执行时间。