float的访问说明符不符合预期

时间:2015-02-07 19:44:44

标签: floating-point

#include <stdio.h>
int main()
{
    printf("%f",5);
}

此代码正在打印0.000000。任何人都可以解释为什么会这样。

4 个答案:

答案 0 :(得分:5)

%f格式需要double参数,您传递int。这是未定义的行为,任何事情都可能发生。你很幸运,发生的事情只是打印0.00000。

在C中,可变参数函数不知道在调用站点传递给它们的参数类型。在printf的情况下,他们只能信任格式字符串来提供该信息。如果参数的类型与(在编译时已知)格式字符串不匹配,任何好的编译器都应该发出警告,我很惊讶你的没有。该函数的实现可以依赖于已应用的默认参数提升,但仅此而已。

实际上,两种常见的情况是参数在堆栈上传递,在这种情况下,在调用站点推送的int5将被解释为64位{{ 1}},或者参数通过寄存器传递,在这种情况下,double函数将从浮点寄存器中获取一个printf值,该值未在调用站点设置并包含剩余的值上次使用它。

答案 1 :(得分:4)

这是因为在您的示例中,5是整数,而不是浮点数。因此,当您使用格式字符串printf将其传递给%f时,您将获得未定义的行为。要使它成为一个浮点数,请使用浮点(5.0)声明它。这将为您提供预期的输出。

实施例

#include <stdio.h>
int main()
{
    printf("%f", 5.0);
}

输出:

5.000000

答案 2 :(得分:3)

这称为未定义行为,因为“%f”需要浮点数或双精度数,但是你给它整数5

未定义的行为意味着编译器可以做任何合法的事情来处理这种情况。

要解决,您有三种选择:

  1. printf("%i", 5)
  2. printf("%f", 5.0)
  3. printf("%f", (double) 5)

答案 3 :(得分:2)

%fdouble类型(或float的格式说明符,它会在变量参数列表中自动提升为double,但您可以使用int。重新传递int。正如其他回答者正确指出的那样,这是未定义的行为。

但为什么输出为零而不是某些其他垃圾值?这需要了解最常见的floating-point format

最可能发生的事情是你的(可能)32位double值被零扩展到64位%f值,这样这些额外的32位零填充符号位,11位指数和有效位数的前20位。这导致denormal值非常接近零,定点0.00000格式将其舍入为%e。使用%gprintf("%f", 5.0)格式可能会显示一个很小但非零的值。

同样,这只是一个实现细节,不同的C实现可能会产生不同的输出,或导致分段错误。

你可能意味着写的是

  • %f(使用printf("%d", 5)格式的正确数据类型)或
  • int(使用printf类型的正确格式字符串)

要防止意外使用不匹配的printf("%f", 5)调用-Wall,请启用编译器警告(例如,使用GCC的{{1}}选项),并注意编译程序时就可以了。