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
的情况下,他们只能信任格式字符串来提供该信息。如果参数的类型与(编译时已知的)格式字符串不匹配,任何好的编译器都应该发出警告,我很惊讶你的没有。该函数的实现可以依赖于已应用的默认参数提升,仅此而已。
实际上,两种常见情况是参数在堆栈上传递,在这种情况下,在调用站点推送的 int
值 5
将被解释为 64 位double
,或者参数通过寄存器传递,在这种情况下,printf
函数将从浮点寄存器中获取一个 double
值,该值未在调用站点设置并包含任何值上次使用时留在那里。
这称为未定义行为,因为“%f”需要浮点数或双精度数,但您给它的是整数 5
。
未定义的行为意味着编译器可以做任何合法的事情来处理这种情况。
要解决,你有三个选择:
printf("%i", 5)
printf("%f", 5.0)
printf("%f", (double) 5)
这是因为在您的示例中,5
是整数,而不是浮点数。因此,当您使用格式字符串 %f
将其传递给 printf
时,您会得到未定义的行为。要使其成为浮点数,请使用浮点数 (5.0
) 声明它。这将为您提供预期的输出。
示例:
#include <stdio.h>
int main()
{
printf("%f", 5.0);
}
输出:
5.000000
%f
是 double
类型的格式说明符(或 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
选项) , 编译程序时要注意它们。
#include <stdio.h>
int main()
{
printf("%f",5);
}
此代码正在打印 0.000000。任何人都可以解释为什么会这样。
%f
格式需要一个 double
参数,而您传递的是 int
。这是未定义的行为,任何事情都可能发生。你很幸运,发生的只是 0.00000 的打印。
在 C 中,可变参数函数不知道在调用点传递给它们的参数的类型。在 printf
的情况下,他们只能信任格式字符串来提供该信息。如果参数的类型与(编译时已知的)格式字符串不匹配,任何好的编译器都应该发出警告,我很惊讶你的没有。该函数的实现可以依赖于已应用的默认参数提升,仅此而已。
实际上,两种常见情况是参数在堆栈上传递,在这种情况下,在调用站点推送的 int
值 5
将被解释为 64 位double
,或者参数通过寄存器传递,在这种情况下,printf
函数将从浮点寄存器中获取一个 double
值,该值未在调用站点设置并包含任何值上次使用时留在那里。
这称为未定义行为,因为“%f”需要浮点数或双精度数,但您给它的是整数 5
。
未定义的行为意味着编译器可以做任何合法的事情来处理这种情况。
要解决,你有三个选择:
printf("%i", 5)
printf("%f", 5.0)
printf("%f", (double) 5)
这是因为在您的示例中,5
是整数,而不是浮点数。因此,当您使用格式字符串 %f
将其传递给 printf
时,您会得到未定义的行为。要使其成为浮点数,请使用浮点数 (5.0
) 声明它。这将为您提供预期的输出。
示例:
#include <stdio.h>
int main()
{
printf("%f", 5.0);
}
输出:
5.000000
%f
是 double
类型的格式说明符(或 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
选项) , 编译程序时要注意它们。