简体   繁体   English

printf%f如何在32位浮点数上运行

[英]How does printf %f work on a 32-bit float

The %f printf format code is specified as operating on a value of type double [ source ]. %f printf格式代码被指定为对double [ source ]类型的值进行操作。 However, a simple test program demonstrates that it can also be used with values of type float . 但是,一个简单的测试程序表明它也可以与float类型的值一起使用。 How does this work? 这是如何运作的?

The equivalent case with integer types (eg int and long long int ) "works" because on little-endian machines, the low-order bytes of a 32-bit integer happen to overlap the low-order bytes of a 64-bit integer, so as long as the upper bits are 0, you'll get the "right" answer. 具有整数类型的等效情况(例如intlong long int )“起作用”,因为在小端机器上,32位整数的低位字节恰好与64位整数的低位字节重叠,所以只要高位为0,你就会得到“正确”的答案。

But this cannot possibly be the case for float and double , because the floating point formats are not interchangeable like this. 但这不可能是floatdouble的情况,因为浮点格式不能像这样互换。 You simply cannot print a floating point value as a double without doing the (rather complicated) conversion into the other format. 如果没有将(相当复杂的)转换为其他格式,您根本无法将浮点值打印为double。 An attempt to do so by type-punning will simply print garbage. 通过类型惩罚尝试这样做只会打印垃圾。

On top of that, printf is variadic. 最重要的是, printf是可变的。 The compiler doesn't necessarily know at compile time what format specifiers will be used, only the types of the arguments. 编译器在编译时不一定知道将使用什么格式说明符,只知道参数的类型。 Therefore the only thing I can surmise is that all float values passed to a variadic function would be upgraded to double , unconditionally. 因此,我唯一可以推测的是,传递给可变函数的所有 float值都将无条件地升级为double But it boggles my mind that I could have been programming in C for so long and not know this. 但令人难以置信的是,我本可以在C语言编程这么长时间而且不知道这一点。

How is C doing the implicit coercion here? C如何在这里进行隐式强制?

Source: 资源:

#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;
}

Output: 输出:

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

Compile command and version: 编译命令和版本:

$ 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. 因此,我唯一可以推测的是,传递给可变函数的所有浮点值都将无条件地升级为double。

Yes - that's precisely right. 是的 - 这是完全正确的。

From the C standard; 从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. 6.5.2.2.7函数原型声明符中的省略号表示法导致参数类型转换在最后声明的参数之后停止。 The default argument promotions are performed on trailing arguments. 默认参数提升是在尾随参数上执行的。

And the "default argument promotions" rules will promote float to double , the relevant part being: 而“默认参数促销”规则将促使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. 6.5.2.2.6如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将类型为float的参数提升为double。

See 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 . 整数类型的每个参数都经历整数提升(见下文), float类型的每个参数都隐式转换为double类型

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

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