繁体   English   中英

该程序如何工作?

[英]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字节的doublefloatprintf()内转换为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

%d是十进制

%f浮动

在这里看到更多这些。

由于浮点数和整数表示方式不同,因此得到0。

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

不是整数。 尝试使用%f

您要%f而不是%d

嘿,它必须打印一些东西,所以它打印了0。请记住,在C 0中还有其他所有内容!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM