【问题标题】:Win10 broke printf functionWin10破解printf函数
【发布时间】:2021-03-22 16:37:32
【问题描述】:
#include <stdio.h>
int main()
{
    float f = 1717.7890625;
    printf( "%.6f", f );
    return 0;
}

我使用 Visual Studio 19 (16.9.2) for x64 arch 编译了这段代码,并在我的两台 Windows 10 PC 上运行了结果:

  1. 版本 1909(操作系统内部版本 18363.1440)-> 调试和发布:1717.789063
  2. 2004 版(操作系统内部版本 19041.867)-> 调试:1717.789063 发布:1717.789062

新版本的Debug和Release结果不同的原因是什么?如何修复它以使两个版本的结果相同?

补充: 代码:

#include <stdio.h>
int main()
{
    double f = 0.25;
    printf( "%.1f", f );
    return 0;
}

在新旧 Win10 版本上具有相同的行为。我建议,这是较新的 ucrtbase.dll 版本中的错误

【问题讨论】:

  • 使用1717.7890625f 有什么不同吗?您现在正在为浮点数分配双精度(IIRC)。
  • 我不认为任何一种行为(向上舍入或向下舍入)都值得“破坏”一词;任何一种行为都是有效的。
  • 可能发布版本优化了f 并直接使用双精度值。调试版本会将双精度值存储到浮点数中(截断它),然后将其转换回双精度值以传递给printf。如果使用cout 而不是printf,会得到什么结果?
  • 事实上,如果您转到h-schmidt.net/FloatConverter,您会发现 1717.7890625 完全可以用 IEEE 32 位浮点数表示。可能是由于一些库更改 - 1909 与 2004 上安装的内容,以及调试与发布的一些不幸差异,可能与浮点标志(您通常从不接触)有关。
  • 1717.789063f1717.789062f 的数字对于 floats 是相同的,1717.789063f == 1717.789062f 将评估为 true。

标签: c windows-10 printf


【解决方案1】:

我找到了导致 Windows 版本和调试/发布模式之间程序行为如此不同的原因。

新的 Windows 更新(19041.* 如果我理解正确)更改了浮点类型小数部分的舍入规则:以前它在以 5 结尾的情况下舍入到更大:1.25 -&gt; 1.3,但现在它舍入到最近偶数:1.25 -&gt; 1.21.35 -&gt; 1.4

要了解在新 Win 10 版本上调试和发布之间的区别,需要注意 ucrtbase.dll 使用和更新规则。

  1. 每个应用程序的调试和发布版本都使用 ucrtbase.dllucrtbased.dll 来自 C:\Windows\System32 或 C:\Windows\SysWOW64
  2. 它的发布版本 (ucrtbase.dll)是 Windows 10 的一部分,只能通过 Windows 更新进行更新。但它的调试版本 (ucrtbased.dll) 不会随 Win 10 更新而更新,但可以通过安装较新的 Windows 10 SDK(例如,在 Visual Studio Installer 中)进行更新。

因此,解决方案是在新的 Windows 10 版本上安装新的 Windows 10 SDK 以实现相同的行为或将 printf() 函数从 https://github.com/fmtlib/fmt 切换到 fmt::printf() 函数,例如,使结果为在所有 Windows 版本上都相同。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-02
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多