为什么C中的double会比C ++打印更少的十进制数字?

我在C中有这个代码,我已经宣布0.1为double。

#include  int main() { double a = 0.1; printf("a is %0.56f\n", a); return 0; } 

这是它打印的, a is 0.10000000000000001000000000000000000000000000000000000000

C ++中的代码相同,

 #include  using namespace std; int main() { double a = 0.1; printf("a is %0.56f\n", a); return 0; } 

这是它打印的, a is 0.1000000000000000055511151231257827021181583404541015625

有什么不同? 当我读到两个都被分配8个字节? C ++如何在小数位上打印更多数字?

另外,它怎么能到小数点55位? IEEE 754浮点只有52位的小数,我们可以得到15位十进制数的精度。 它以二进制forms存储。 为什么它的十进制解释存储更多?

使用MinGW g ++(和gcc)7.3.0,您的结果将被准确复制。

这是一个非常奇怪的未定义行为案例。

未定义的行为是由于使用了printf而没有包含一个合适的标题,¹违反了“应该”

C ++17§20.5.2.2

翻译单位应仅在任何声明或定义之外包括标题,并且应在该翻译单位的第一次参考之前以词汇方式将标题包含在该标题中声明的任何实体之前。 无需诊断。

在C ++代码中,将更改为 ,以获得有效的C ++代码 ,并获得与C程序相同的结果。


为什么C ++代码甚至可以编译?

好吧,与C不同,在C ++中,允许标准库头在任何其他头中拖动。 显然,使用g ++, 标头拖入了printf一些声明。 只是不完全正确。

详细信息:使用MinGW g ++ 7.3.0, printf的声明/定义取决于宏符号__USE_MINGW_ANSI_STDIO 。 默认只是声明printf 。 但是当__USE_MINGW_ANSI_STDIO被定义为逻辑真时, 提供了printf的重写定义,即调用__mingw_vprintf 。 并且在包含之前, 标头定义(通过间接包含) __USE_MINGW_ANSI_STDIO

<_mingw.h>有一条注释,“请注意,我们也在C ++中为_GNU_SOURCE启用它,但不支持C情况。”

在C ++中,对于这个编译器的相关版本,包含和使用printf ,或包括using std::printf;之间实际上有区别using std::printf; ,并使用printf


关于

另外,它怎么能到小数点55位? IEEE 754浮点只有52位的小数,我们可以得到15位十进制数的精度。 它以二进制forms存储。 为什么它的十进制解释存储更多?

……只是十进制表示更长。 超出内部表示精度的数字,对于64位IEEE 754约为15位,基本上是垃圾,但它们可用于精确地重构原始位。 在某些时候,它们将变为全零,并且达到C ++程序输出中最后一位的那一点。


1感谢Dietrich Epp发现标准报价。

在我看来,两种情况都打印56位小数,所以问题在技术上是基于一个有缺陷的前提。

我还看到两个数字在52位精度内等于0.1 ,因此两者都是正确的。

这导致你的最后一个问题,“它的十进制解释如何存储更多?”。 它不存储更多小数。 double不存储任何小数。 它存储位。 生成小数。