当在printf中使用%d时,float变量会发生什么?

我正在尝试通过阅读C编程语言第2版来学习C. 我有一些编程经验,但没有C.

我目前在第1章。我有以下代码:


float f; for (f = 0.0; f <= 3; f += 1.1) printf("A: %3f B: %6.2f\n", f, f + 0.15); 

它打印输出:

 A: 0.000000 B: 0.15 A: 1.100000 B: 1.25 A: 2.200000 B: 2.35 

看起来很好。


现在我按如下方式更改printf:

 printf("A: %3d B: %6.2f\n", f, f + 0.15); 

新的输出是

 A: 0 B: 0.00 A: -1610612736 B: 0.00 A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00 

这里发生了什么? 我希望浮点数转换为int因为我使用了%d,但事实并非如此。 另外,为什么价值B也出错? 这里发生了什么事?

你打电话的时候:

 printf("A: %3d B: %6.2f\n", f, f + 0.15); 

C自动将float值转换为double (它是在调用带有变量参数的函数时进行的标准转换,例如int printf(const char *fmt, ...); )。 为了论证,我们假设sizeof(int)是4而sizeof(double)是8(有例外,但它们很少而且很远)。

因此,该调用已将指针推入堆栈,加上f的8字节双f ,以及f + 0.15另一个8字节双f + 0.15 。 当它处理格式字符串时, %d告诉printf()你在格式字符串之后将一个4字节的int推入堆栈。 由于这不是你所做的,你已经调用了未定义的行为; 根据C标准,接下来发生的一切都没问题。

然而,最有可能的实现轻快地读取4个字节并将它们打印成好像是一个int (它相信你说实话)。 然后它遇到了%6.2f格式; 它将从堆栈中读取8个字节作为double 。 有一个外部的可能性,这会导致内存错误导致访问错位(它需要64位机器,要求在8字节边界上对齐,例如SPARC),否则它将读取4个字节f和来自f + 0.15 4个字节,将它们组合在一起以创建一些相当意外的double值 – 正如您的示例所示。

无论你告诉它,Printf都会将你指向的记忆对待。 没有转换。 它将表示float的内存视为int。 因为两者的存储方式不同,所以你得到的本质上是一个随机数。

如果要将float输出为整数,则应首先将其转换为:

 printf("A: %3d B: %6.2f\n", (int)f, f + 0.15);