这个程序如何工作?

#include <stdio.h> int main() { float a = 1234.5f; printf("%d\n", a); return 0; } 

它显示一个0 ! 这怎么可能? 什么是推理?


我有意在printf语句中join%d来研究printf的行为。

这是因为%d期望一个int但是你提供了一个浮点数。

使用%e / %f / %g打印浮点数。


为什么打印0:在发送到printf之前,浮点数被转换为double 。 小尾数的双重表示的数字是1234.5

 00 00 00 00 00 4A 93 40 

%d消耗一个32位整数,所以打印一个零。 (作为一个testing,你可以printf("%d, %d\n", 1234.5f);你可以得到输出0, 1083394560 。)


至于为什么float被转换为double ,因为printf的原型是从6.5.2.2/7开始的int printf(const char*, ...)

函数原型声明符中的省略号表示法导致参数types转换在最后声明的参数后停止。 在结尾参数上执行默认参数促销。

从6.5.2.2/6开始,

如果表示被调用函数的expression式的types不包含原型,则对每个参数执行整数提升, 并将具有floattypes的参数提升为double 这些被称为默认参数促销

(感谢Alok找出答案。)

从技术上说,没有printf ,每个库都实现它自己,因此,你试图通过做你正在做的事来研究printf的行为的方法不会太有用。 你可能试图研究你系统中printf的行为,如果是这样,你应该阅读文档,并查看printf的源代码(如果它适用于你的库)。

例如,在我的Macbook上,我的输出是1606416304

话虽如此,当您将一个float传递给一个可变参数函数时, float将以doubleforms传递。 所以,你的程序相当于宣布a一个double

为了检查一个double的字节,你可以在SO上看到最近一个问题的答案 。

让我们这样做:

 #include <stdio.h> int main(void) { double a = 1234.5f; unsigned char *p = (unsigned char *)&a; size_t i; printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int)); for (i=0; i < sizeof a; ++i) printf("%02x ", p[i]); putchar('\n'); return 0; } 

当我运行上面的程序时,我得到:

 size of double: 8, int: 4 00 00 00 00 00 4a 93 40 

所以, double的前四个字节就是0,这可能是为什么你得到0作为printf调用的输出。

为了获得更有趣的结果,我们可以稍微改变一下程序:

 #include <stdio.h> int main(void) { double a = 1234.5f; int b = 42; printf("%d %d\n", a, b); return 0; } 

当我在Macbook上运行上述程序时,我得到:

 42 1606416384 

在Linux机器上使用相同的程序,我得到:

 0 1083394560 

%d说明符告诉printf期望一个整数。 所以float的前四个(或两个,取决于平台)字节被解释为一个整数。 如果它们碰巧为零,则打印一个零

1234.5的二进制表示是类似的

 1.00110100101 * 2^10 (exponent is decimal ...) 

用一个C编译器来表示实际上是IEEE754 double值的float ,字节将是(如果我没有犯错的话)

 01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000 

在Intel(x86)系统中,只有less数字节(即最低有效字节先进入),这个字节序列反转,使得前四个字节为零。 也就是说, printf打印出来的东西

根据IEEE754,请参阅本维基百科文章的浮点表示。

因为你调用了未定义的行为:你违背了printf()方法的约定,通过说谎它的参数types,所以编译器可以自由地做任何事情。 它可以使程序输出“dksjalk是一个忍者!!!” 从技术上讲这还是对的。

这是因为二进制浮点数的表示。 转换为一个整数将其保留为0。

原因是printf()是一个非常笨的函数。 它根本不检查types。 如果你说第一个参数是一个int (这就是你说的%d ),它相信你,它只需要一个int所需的字节。 在这种情况下,假设你的机器使用了4字节的int和8字节的doublefloatprintf()被转换成了double ),a的前4个字节就是0,并且打印出来。

它不会自动浮点转换为整数。 因为两者都有不同的存储格式。 所以如果你想转换,使用(int)types转换。

 #include <stdio.h> int main() { float a = 1234.5f; printf("%d\n", (int)a); return 0; } 

由于您也使用C ++标记了该代码 , 因此此代码按照您的预期进行转换:

 #include <iostream.h> int main() { float a = 1234.5f; std::cout << a << " " << (int)a << "\n"; return 0; } 

输出:

 1234.5 1234 

%d是十进制

%f是浮点数

在这里看到更多。

你得到0,因为浮动和整数是不同的代表。

您只需要使用相应的数据types(int,float,string等)的格式说明符(%d,%f,%s等)。

你想%f不是%d

嘿,它不得不打印一些东西,所以它打印0.记住在C 0是一切!

这不是一个整数。 尝试使用%f