88
#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", a);
    return 0;
}

它显示一个0!! 这怎么可能?原因是什么?


我特意%dprintf语句中放了一个来研究printf.

4

13 回答 13

239

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

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


关于为什么打印 0:浮点数double在发送到之前转换为printf. little endian 中双重表示的数字 1234.5 是

00 00 00 00  00 4A 93 40

A%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 发现这一点。)

于 2010-03-04T08:23:34.980 回答
45

从技术上讲,没有 printf每个库都实现了自己的,因此,您尝试printf通过做您正在做的事情来研究 的行为的方法不会有太大用处。您可能正在尝试研究printf系统上的行为,如果是这样,您应该阅读文档,并查看源代码printf是否可用于您的库。

例如,在我的 Macbook 上,我1606416304通过您的程序获得输出。

话虽如此,当您将 a 传递float给可变参数函数时, thefloat将作为 a 传递double。因此,您的程序相当于已声明adouble.

要检查 a 的字节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 

因此,结果的前四个字节为double0,这可能就是您得到调用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
于 2010-03-04T08:45:26.247 回答
20

说明%d符告诉printf期望一个整数。因此,浮点数的前四个(或两个,取决于平台)字节被解释为整数。如果它们恰好为零,则打印零

1234.5 的二进制表示类似于

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

使用实际上表示为 IEEE754 双值的 C 编译器float,字节将是(如果我没记错的话)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

在字节顺序很小的 Intel (x86) 系统上(即最不重要的字节首先出现),此字节序列被反转,因此前四个字节为零。也就是说,printf打印出来的...

有关根据 IEEE754 的浮点表示,请参阅此 Wikipedia 文章。

于 2010-03-04T08:20:32.883 回答
8

因为你调用了未定义的行为:你违反了 printf() 方法的约定,因为它在参数类型上撒谎,所以编译器可以随意做任何事情。它可以使程序输出“dksjalk is a ninnyhead!!!” 从技术上讲,它仍然是正确的。

于 2010-03-04T08:21:37.233 回答
7

这是因为浮点数以二进制表示。转换为整数后,其值为 0。

于 2010-03-04T08:19:39.717 回答
5

原因是这printf()是一个非常愚蠢的功能。它根本不检查类型。如果您说第一个参数是 an int(这就是您所说的%d),它相信您并且它只需要 an 所需的字节int。在这种情况下,假设您的机器使用 4 字节int和 8 字节doublefloat转换为doubleinside printf()), 的前四个字节a将只是零,并且会打印出来。

于 2010-03-04T08:21:26.387 回答
3

它不会自动将浮点数转换为整数。因为两者都有不同的存储格式。因此,如果要转换,请使用 (int) 类型转换。

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}
于 2010-03-04T08:22:41.287 回答
2

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

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

输出:

1234.5 1234
于 2010-03-04T08:25:00.487 回答
1

%d是十进制

%f是浮动的

在这里查看更多。

你得到 0 因为浮点数和整数的表示方式不同。

于 2010-03-04T08:19:28.440 回答
1

您只需将适当的格式说明符(%d、%f、%s 等)与相关数据类型(int、float、string 等)一起使用。

于 2010-03-04T10:14:07.863 回答
0

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

于 2010-03-04T08:17:19.583 回答
0

你想要 %f 而不是 %d

于 2010-03-04T08:18:05.680 回答
0

嘿,它必须打印一些东西,所以它打印了一个 0。记住在 C 中 0 是其他一切!

于 2010-03-04T09:12:11.333 回答