gpt4 book ai didi

c# - Windows 7 64 位中的递归

转载 作者:行者123 更新时间:2023-11-30 20:56:30 25 4
gpt4 key购买 nike

我有这个助手类

public static class DateTimeHelper
{
public static int GetMonthDiffrence(DateTime date1, DateTime date2)
{
if (date1 > date2)
{
return getmonthdiffrence(date2, date1);
}
else
{
return ((date2.year - date1.year) * 12) + (date2.month - date1.month);
}
}
}

函数计算两个日期之间的月数,它完全符合我的要求。到目前为止没有问题。

问题是当我在发布和 windows 7 64 位时,我总是得到相同的值“0”

当我深入研究这个问题时,我意识到在某个时候,由于递归调用,两个参数是相等的。

我重复一遍,只有当我在 windows 7 64 位上构建未附加到调试器的发行版时,我才会遇到此错误。

任何人都可以知道这种行为吗?如果是这样,我需要一些链接以获取更多详细信息。

这是 IL 代码。 (我觉得可以帮助理解更多)

.class public auto ansi abstract sealed beforefieldinit Helpers.DateTimeHelper
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig static
int32 GetMonthDiffrence (
valuetype [mscorlib]System.DateTime date1,
valuetype [mscorlib]System.DateTime date2
) cil managed
{
// Method begins at RVA 0x6a658
// Code size 52 (0x34)
.maxstack 8

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call bool [mscorlib]System.DateTime::op_GreaterThan(valuetype [mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
IL_0007: brfalse.s IL_0011

IL_0009: ldarg.1
IL_000a: ldarg.0
IL_000b: call int32 Helpers.DateTimeHelper::GetMonthDiffrence(valuetype [mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
IL_0010: ret

IL_0011: ldarga.s date2
IL_0013: call instance int32 [mscorlib]System.DateTime::get_Year()
IL_0018: ldarga.s date1
IL_001a: call instance int32 [mscorlib]System.DateTime::get_Year()
IL_001f: sub
IL_0020: ldc.i4.s 12
IL_0022: mul
IL_0023: ldarga.s date2
IL_0025: call instance int32 [mscorlib]System.DateTime::get_Month()
IL_002a: ldarga.s date1
IL_002c: call instance int32 [mscorlib]System.DateTime::get_Month()
IL_0031: sub
IL_0032: add
IL_0033: ret
} // end of method DateTimeHelper::GetMonthDiffrence
}

编辑:

如果您想重现问题,这里有一个测试程序:

class Program
{
static void Main(string[] args)
{
for (int i = 2000; i < 3000; i++)
{
var date1 = new DateTime(i, 1, 1);
var date2 = new DateTime(i + 1, 1, 1);
var monthdiff = DateTimeHelper.GetMonthDiffrence(date2, date1);
if (monthdiff == 0)
Console.WriteLine(string.Format("date1 => {0}, date2 => {1}, diff=> {2}", date2, date1, monthdiff.ToString()));
}
Console.WriteLine("done!");
Console.ReadKey();
}
}

您必须在 Release模式和 64 位配置上构建项目,然后转到构建结果的位置并执行程序。提前致谢。我最诚挚的问候。

最佳答案

我可以在 Windows 7、.Net 4.5、Visual Studio 2012、x64 目标、附带调试器的 Release模式上复制此行为,但禁用“抑制模块加载时的 JIT 优化”。这似乎是尾部调用优化中的一个错误(这就是为什么您只在 x64 上获得它的原因)。

IL 在这里并不重要, native 代码很重要。 GetMonthDiffrence() 的相关代码部分是:

0000005e  cmp         rdx,rcx 
00000061 setg al
00000064 movzx eax,al
00000067 test eax,eax
00000069 je 0000000000000081 // else branch
0000006b mov rax,qword ptr [rsp+68h]
00000070 mov qword ptr [rsp+60h],rax
00000075 mov rax,qword ptr [rsp+60h]
0000007a mov qword ptr [rsp+68h],rax
0000007f jmp 0000000000000012 // start of the method

重要的部分是 4 条 mov 指令。他们尝试交换 [rsp+68h][rsp+60h](这是存储参数的地方),但是他们做错了,所以最终都得到了相同的值。

有趣的是,如果我从您的 Main() 中删除对 Console.ReadKey() 的调用,代码工作正常,因为对 GetMonthDiffrence( ) 是内联的,在这种情况下不执行尾调用优化。

一种可能的解决方法是将 [MethodImpl(MethodImplOptions.NoInlining)] 添加到您的方法中,这似乎会禁用尾调用优化。

我有submitted this bug on Connect .

关于c# - Windows 7 64 位中的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17483585/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com