代码之家  ›  专栏  ›  技术社区  ›  Elliott Slaughter

printf%f如何在32位浮点上工作

  •  2
  • Elliott Slaughter  · 技术社区  · 7 年前

    这个 %f printf格式代码被指定为对类型的值进行操作 double [ source ]然而,一个简单的测试程序证明它也可以与类型的值一起使用 float . 这是怎么工作的?

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

    但这不可能是 浮动 双重的 ,因为浮点格式不能像这样互换。如果不将浮点值转换为其他格式(相当复杂),则无法将其作为双精度值打印。通过类型punning尝试这样做只会打印垃圾。

    最重要的是, printf 是多变的。编译器不一定在编译时知道将使用什么格式说明符,只知道参数的类型。因此,我只能猜测 全部的 浮动 传递给变量函数的值将升级为 双重的 ,无条件。但它让我很困惑,我本来可以在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.
    
    2 回复  |  直到 7 年前
        1
  •  4
  •   0x5453 Yuki    7 年前

    Variadic arguments Default argument promotions :

    在函数调用中,作为变量参数列表一部分的每个参数都会进行特殊的隐式转换,称为 default argument promotions .

    .

    integer类型的每个参数都进行integer提升(见下文),并且 float类型的每个参数都隐式转换为double类型 .

        2
  •  5
  •   nos    7 年前

    因此,我只能猜测,传递给变量函数的所有浮点值都将无条件升级为double。

    是的-没错。

    来自C标准;

    6.5.2.2.7函数原型声明符中的省略号表示法导致参数类型转换在最后一次声明后停止。 参数。默认参数升级是在尾部执行的 争论。

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

    6.5.2.2.6如果表示被调用函数的表达式具有不包含原型的类型,则整数提升为 对每个参数执行,具有float类型的参数为 提升到双倍。