[英]How does this program work?
#include <stdio.h>
int main() {
float a = 1234.5f;
printf("%d\n", a);
return 0;
}
它显示0
! 那怎么可能? 这是什么原因?
我特意在printf
语句中添加了一个%d
来研究printf
的行为。
这是因为%d
需要一个int
但是您提供了一个float值。
使用%e
/ %f
/ %g
打印浮点数。
关于为什么打印0的原因:将浮点数转换为double
然后发送给printf
。 小尾数中双精度表示形式的数字1234.5为
00 00 00 00 00 4A 93 40
%d
使用32位整数,因此打印为零。 (作为测试,您可以printf("%d, %d\\n", 1234.5f);
可以得到输出0, 1083394560
。)
至于为什么将float
转换为double
,因为printf的原型是int printf(const char*, ...)
从6.5.2.2/7开始,
函数原型声明器中的省略号引起参数类型转换在最后声明的参数之后停止。 默认参数提升是对尾随参数执行的。
从6.5.2.2/6开始,
如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升, 而将
float
类型的参数提升为double
。 这些称为默认参数提升 。
(感谢Alok找出这个问题。)
从技术上讲不存在printf
,每个库实现了自己,因此,你的努力学习方法printf
做你正在做什么的行为是不会有太大的用处。 您可能正在尝试研究系统上printf
的行为,如果是这样,则应阅读文档,并查看printf
的源代码(如果库可用)。
例如,在我的Macbook上,我的程序输出为1606416304
。
话虽如此,当您将float
传递给可变参数函数时, float
作为double
传递。 因此,您的程序等同于将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,这可能就是为什么printf
调用的输出为0
原因。
为了获得更有趣的结果,我们可以对程序进行一些更改:
#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
期望一个整数。 因此,浮点数的前四个(或两个,取决于平台)字节被解释为整数。 如果它们恰好为零,则打印零
1234.5的二进制表示形式类似于
1.00110100101 * 2^10 (exponent is decimal ...)
使用C编译器实际上将float
表示为IEEE754双float
值,则字节将是(如果我没有记错的话)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
在字节序很少的Intel(x86)系统上(即,最低有效字节排在最前面),该字节序列取反,因此前四个字节为零。 也就是说, printf
打印出什么...
有关IEEE754的浮点表示,请参见此Wikipedia文章 。
这是因为浮点数以二进制表示。 转换为整数会使它保留为0。
因为您调用了未定义的行为:您对它的参数类型说谎,从而违反了printf()方法的约定,所以编译器可以自由地执行自己喜欢的事情。 它可能使程序输出“ dksjalk是一个ninnyhead !!!” 从技术上讲,这仍然是正确的。
原因是printf()
是一个非常愚蠢的函数。 它根本不检查类型。 如果您说第一个参数是int
(这就是您使用%d
所说的话),则它会相信您,并且只占用int
所需的字节。 在这种情况下,假设您的机器使用4字节的int
和8字节的double
( float
在printf()
内转换为double
),则a
的前四个字节将仅为零,并且将其打印出来。
它不会自动将float转换为整数。 因为两者具有不同的存储格式。 因此,如果要转换,请使用(int)类型转换。
#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
您只需要使用具有相关数据类型(int,float,string等)的适当格式说明符(%d,%f,%s等)。
不是整数。 尝试使用%f
。
您要%f而不是%d
嘿,它必须打印一些东西,所以它打印了0。请记住,在C 0中还有其他所有内容!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.