这个程序如何工作?
#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不包含原型,则对每个参数执行整数提升, 并将具有
float
types的参数提升为double
。 这些被称为默认参数促销 。
(感谢Alok找出答案。)
从技术上说,没有printf
,每个库都实现它自己,因此,你试图通过做你正在做的事来研究printf
的行为的方法不会太有用。 你可能试图研究你系统中printf
的行为,如果是这样,你应该阅读文档,并查看printf
的源代码(如果它适用于你的库)。
例如,在我的Macbook上,我的输出是1606416304
。
话虽如此,当您将一个float
传递给一个可变参数函数时, float
将以double
forms传递。 所以,你的程序相当于宣布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字节的double
( float
在printf()
被转换成了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
。