【发布时间】:2021-03-30 05:41:56
【问题描述】:
最近,我在玩 C 来测试不同的东西。
printf("%d", 0.4);
将打印 -1717986918。
我知道这一定与浮点数的二进制表示有关。但是,使用一些在线资源将 0.4 转换为浮点数后,二进制表示与 -171986918 不匹配。请解释一下这段代码背后到底发生了什么。
PS:我正在使用 gcc 编译器并在 Windows 64 位上运行它。
【问题讨论】:
-
sizeof(int)和sizeof(double)(0.4可能是)具有不同的字节数(很可能)。 -
常量
0.4的类型为double。因此,它与%d指令没有正确匹配,导致您的printf调用具有未定义的行为。 “实际发生”的情况取决于您对printf的实施细节,也可能取决于其他因素。除了学习必须正确键入将printf参数与格式字符串匹配的课程之外,这不是一个有用的细节。无论您发现什么细节都无法可靠地转移。 -
请注意,如果您启用警告(例如
gcc -Wall),printf语句将被编译器标记。 -
一些系统——macOS Mojave 10.14.6 是一个,但我相信 Linux x86/64 是另一个——有一个 ABI 可以在不同的寄存器集中传递整数和双精度值。这意味着如果您没有将编译器设置为 fussy,您会从
printf("Integer: %4d; double: %13.6g\n", 3.141592654, 9876);获得“正确”结果——也就是说,它会产生“Integer: 9876; double: 3.14159, give or take some spaces. That's because whenprintf()` 处理 @987654335 @,它从整数寄存器中取出第一个整数,当它处理%13.6g时,它从浮点寄存器中取出第一个双精度数。 -
你不能依赖这种行为。大多数历史系统不会那样做。但是(至少有一些)正在使用的 x86/64 ABI 会导致这种滥用。
标签: c floating-point printf