提问人:wkl 提问时间:4/6/2017 最后编辑:wkl 更新时间:4/6/2017 访问量:90
(如何)调试会改变程序的工作流程?
(How) does debugging change the workflow of the program?
问:
请考虑以下简单程序:
var dblMax = Double.MaxValue;
var result = (dblMax * 1000) / 1800;
Console.WriteLine(result);
当我在调试模式下构建它并运行 (Ctrl+F5) 或调试 (F5) 它时,它会打印 .9.987140856842E+307
当我切换到发布模式并运行 (Ctrl+F5) 它时,它会无限打印。8
我知道这种差异是由于在发布模式下完成的一些编译器优化造成的。
但是,如果我在发布模式下调试 (F5) 相同的版本,它会再次打印!9.987140856842E+307
我正在调试的事实如何改变计算结果?
编辑:
我不问为什么调试模式和发布模式会产生不同的结果。我想知道为什么发布模式会产生不同的结果,具体取决于我是否调试 (F5) 或是否 (Ctrl+F5)。
答:
这与浮点精度密切相关。在调试模式下,编译器使用 80 位精度。在发布模式下,编译器使用 64 位截断结果。
何时发生这种情况取决于多个配置、设置和环境变量。例如,您可以关闭发布模式配置的优化。这应该会有所帮助。
看看这个 Jon Skeet 的答案: https://stackoverflow.com/a/18417944/637840
评论
调试时,JITter 的行为会有所不同。
首先,在许多情况下,局部变量的生存期会发生变化,以便进行检查。请考虑在计算期间使用变量后命中断点。如果 JITter 知道该变量不会在表达式之后使用,并且它没有延长变量的生存期,则最终可能无法查看该变量,这是调试的核心功能。
JITer 非常清楚地知道变量何时有用。如果在此期间有寄存器可用,它最终可能会使用此寄存器来存储变量。
但是,在附加调试器的情况下,它可能会决定改用内存位置,因为生存期发生了足够的变化,因此寄存器不可用于该部分代码。
CPU 的浮点寄存器比相应的浮点存储格式具有更高的精度,这意味着一旦您将一个值从寄存器中取出并存入内存,或者只是将其一直存储在内存中,您将体验到较低的精度。
RELEASE 和 DEBUG 构建之间的差异最终可能决定了这些事情,调试器的存在也是如此。
此外,不同的 .NET 运行时版本之间可能存在差异,这可能会影响这一点。
正确编写浮点代码需要深入了解您正在尝试执行的操作以及机器和平台的各个部分将如何干扰。我会尽量避免编写这样的代码。
评论
dblMax * 1000