这个程序如何运作?

时间:2010-03-04 08:16:07

标签: c++ c memory printf endianness

#include <stdio.h>

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

显示0 !!怎么可能?是什么原因?


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

13 个答案:

答案 0 :(得分:238)

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

使用%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的参数提升为{{1} }。这些被称为默认参数促销

(感谢Alok发现了这一点。)

答案 1 :(得分:45)

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

例如,在我的Macbook上,我的程序输出1606416304

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

要检查double的字节,您可以在此处查看this answer最近的问题。

我们这样做:

#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

答案 2 :(得分:20)

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

1234.5的二进制表示类似于

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

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

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

在具有少量字节序的英特尔(x86)系统(即最低有效字节首先出现)上,此字节序列被反转,因此前四个字节为零。也就是说,printf打印出来......

根据IEEE754,请参阅This Wikipedia article了解浮点表示。

答案 3 :(得分:7)

这是因为二进制表示浮点数。转换为整数会使其为0.

答案 4 :(得分:7)

因为您调用了未定义的行为:您通过向其说明其参数类型违反了printf()方法的约定,因此编译器可以随意执行任何操作。它可以使程序输出“dksjalk是一个ninnyhead !!!”从技术上讲,它仍然是正确的。

答案 5 :(得分:5)

原因是printf()是一个非常愚蠢的功能。它根本不检查类型。如果你说第一个参数是int(这就是你对%d说的话),它认为你只需要int所需的字节。在这种情况下,假设您的计算机使用四字节int和八字节doublefloat转换为double内的printf(), <{1}}的前四个字节将只是零,并且会打印出来。

答案 6 :(得分:3)

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

#include <stdio.h>

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

答案 7 :(得分:2)

由于您也使用C ++对其进行了标记,this code会按预期进行转换:

#include <iostream.h>

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

输出:

1234.5 1234

答案 8 :(得分:1)

%d是十进制

%f是浮动

查看更多这些here

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

答案 9 :(得分:1)

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

你想要%f而不是%d

答案 12 :(得分:0)

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