printf %f 如何处理 32 位浮点数
How does printf %f work on a 32-bit float
%f
printf 格式代码被指定为对类型 double
[source] 的值进行操作。然而,一个简单的测试程序表明它也可以与 float
类型的值一起使用。这是如何工作的?
整数类型的等效情况(例如int
和long long int
)"works"因为在小端机器上,32位整数的低位字节恰好重叠 64 位整数的低位字节,因此只要高位为 0,您就会得到 "right" 答案。
但是 float
和 double
不可能是这种情况,因为浮点格式不能像这样互换。如果不进行(相当复杂的)转换为其他格式,您根本无法将浮点值打印为双精度值。尝试通过类型双关来做到这一点只会打印垃圾。
最重要的是,printf
是可变的。编译器不一定在编译时知道将使用什么格式说明符,只知道参数的类型。因此,我唯一可以推测的是,传递给可变参数函数的 all float
值将无条件地升级为 double
。但令我感到困惑的是,我可能已经用 C 编程了这么久,却不知道这一点。
C 在这里如何进行隐式强制转换?
来源:
#include <stdio.h>
#include <math.h>
int main() {
float x[2] = {M_PI, 0.0};
printf("value of x: %.16e\n", x[0]);
printf("size of x: %lu\n", sizeof(x[0]));
double *xp = (double *)&x[0];
printf("value of *xp: %.16e\n", *xp);
printf("size of *xp: %lu\n", sizeof(*xp));
double y = M_PI;
printf("value of y: %.16e\n", y);
printf("size of y: %lu\n", sizeof(y));
int i[2] = {1234, 0};
printf("value of i: %lld\n", i[0]);
printf("sizeof of i: %lu\n", sizeof(i[0]));
long long *ip = (long long *)&i[0];
printf("value of i: %lld\n", *ip);
printf("sizeof of i: %lu\n", sizeof(*ip));
return 0;
}
输出:
value of x: 3.1415927410125732e+00
size of x: 4
value of *xp: 5.3286462644388174e-315
size of *xp: 8
value of y: 3.1415926535897931e+00
size of y: 8
value of i: 1234
sizeof of i: 4
value of i: 1234
sizeof of i: 8
编译命令和版本:
$ gcc test_float.c -o test_float
$ gcc --version
gcc (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Therefore the only thing I can surmise is that all float values passed to a variadic function would be upgraded to double, unconditionally.
是的 - 完全正确。
来自C标准;
6.5.2.2.7 The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared
parameter. The default argument promotions are performed on trailing
arguments.
而"default argument promotions"规则会将float
提升为double
,相关部分为:
6.5.2.2.6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are
performed on each argument, and arguments that have type float are
promoted to double.
参见Variadic arguments and Default argument promotions:
At the function call, each argument that is a part of the variable argument list undergoes special implicit conversions known as default argument promotions.
.
Each argument of integer type undergoes integer promotion (see below), and each argument of type float is implicitly converted to the type double.
%f
printf 格式代码被指定为对类型 double
[source] 的值进行操作。然而,一个简单的测试程序表明它也可以与 float
类型的值一起使用。这是如何工作的?
整数类型的等效情况(例如int
和long long int
)"works"因为在小端机器上,32位整数的低位字节恰好重叠 64 位整数的低位字节,因此只要高位为 0,您就会得到 "right" 答案。
但是 float
和 double
不可能是这种情况,因为浮点格式不能像这样互换。如果不进行(相当复杂的)转换为其他格式,您根本无法将浮点值打印为双精度值。尝试通过类型双关来做到这一点只会打印垃圾。
最重要的是,printf
是可变的。编译器不一定在编译时知道将使用什么格式说明符,只知道参数的类型。因此,我唯一可以推测的是,传递给可变参数函数的 all float
值将无条件地升级为 double
。但令我感到困惑的是,我可能已经用 C 编程了这么久,却不知道这一点。
C 在这里如何进行隐式强制转换?
来源:
#include <stdio.h>
#include <math.h>
int main() {
float x[2] = {M_PI, 0.0};
printf("value of x: %.16e\n", x[0]);
printf("size of x: %lu\n", sizeof(x[0]));
double *xp = (double *)&x[0];
printf("value of *xp: %.16e\n", *xp);
printf("size of *xp: %lu\n", sizeof(*xp));
double y = M_PI;
printf("value of y: %.16e\n", y);
printf("size of y: %lu\n", sizeof(y));
int i[2] = {1234, 0};
printf("value of i: %lld\n", i[0]);
printf("sizeof of i: %lu\n", sizeof(i[0]));
long long *ip = (long long *)&i[0];
printf("value of i: %lld\n", *ip);
printf("sizeof of i: %lu\n", sizeof(*ip));
return 0;
}
输出:
value of x: 3.1415927410125732e+00
size of x: 4
value of *xp: 5.3286462644388174e-315
size of *xp: 8
value of y: 3.1415926535897931e+00
size of y: 8
value of i: 1234
sizeof of i: 4
value of i: 1234
sizeof of i: 8
编译命令和版本:
$ gcc test_float.c -o test_float
$ gcc --version
gcc (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Therefore the only thing I can surmise is that all float values passed to a variadic function would be upgraded to double, unconditionally.
是的 - 完全正确。
来自C标准;
6.5.2.2.7 The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.
而"default argument promotions"规则会将float
提升为double
,相关部分为:
6.5.2.2.6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double.
参见Variadic arguments and Default argument promotions:
At the function call, each argument that is a part of the variable argument list undergoes special implicit conversions known as default argument promotions.
.
Each argument of integer type undergoes integer promotion (see below), and each argument of type float is implicitly converted to the type double.