【问题标题】:How does printf %f work on a 32-bit floatprintf %f 如何在 32 位浮点数上工作
【发布时间】:2019-05-11 18:34:33
【问题描述】:

%f printf 格式代码被指定为对 double [source] 类型的值进行操作。但是,一个简单的测试程序表明它也可以用于float 类型的值。这是如何工作的?

整数类型的等效情况(例如int 和long long int)“有效”,因为在小端机器上,32 位整数的低位字节恰好与整数的低位字节重叠64位整数,所以只要高位为0,就会得到“正确”的答案。

但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.

【问题讨论】:

标签: c printf variadic-functions


【解决方案1】:

因此,我唯一可以推测的是,传递给可变参数函数的所有浮点值都将无条件升级为双精度值。

是的 - 完全正确。

来自 C 标准;

6.5.2.2.7 函数原型声明器中的省略号会导致参数类型转换在最后一次声明后停止 范围。默认参数提升在尾随上执行 论据。

并且“默认参数提升”规则会将float提升为double,相关部分为:

6.5.2.2.6 如果表示被调用函数的表达式的类型不包含原型,则整数提升为 对每个参数执行,并且具有浮点类型的参数是 升职加倍。

【讨论】:

    【解决方案2】:

    见Variadic arguments和Default argument promotions:

    在函数调用时,作为变量参数列表一部分的每个参数都会经历特殊的隐式转换,称为default argument promotions。

    .

    整数类型的每个参数都经过整数提升(见下文),float 类型的每个参数都隐式转换为 double 类型。

    【讨论】:

      猜你喜欢
      • 2015-06-09
      • 1970-01-01
      • 2020-09-04
      • 2011-12-14
      • 1970-01-01
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 2013-08-26
      相关资源
      最近更新 更多