float 的访问说明符未按预期运行

Access specifier for float does not behave as expected

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

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

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

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

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

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

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

要解决,你有三个选择:

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

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

示例:

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

输出:

5.000000

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

但为什么输出 zero 而不是一些 other 垃圾值?这需要对最常见的floating-point format.

有一点了解

最有可能发生的是您的(可能)32 位 int 值正在零扩展到 64 位 double 值,这样这些额外的 32 位零位填充符号位、11 位指数和尾数的前 20 位。这导致 denormal 值非常接近于零,以至于定点 %f 格式将其四舍五入为 0.00000。使用 %e%g 格式可能会显示一个小但非零的值。

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

您可能想要写的是

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

为了防止 意外 使用不匹配的 printf 调用,如 printf("%f", 5),启用编译器警告(例如,在 GCC 中使用 -Wall 选项) , 编译程序时要注意它们。