为什么printf()将float提升为double?

27 c c++ floating-point printf variadic-functions

从上一个问题:

如果你试图传递floatprintf它,它会doubleprintf收到它之前被提升

printf()是一个可变函数吧?可变参数函数在传递之前是否会提升float参数double

Sha*_*our 26

是的,variadic函数的float参数被提升为double.

C99标准草案部分6.5.2.2函数调用说:

[...]并且类型为float的参数被提升为double.这些被称为默认参数促销.[...]

草案C++标准部分5.2.2函数调用:

[...]浮点类型受浮点提升(4.6)影响,参数值在调用之前转换为提升类型.[...]

和部分4.6:

float类型的prvalue可以转换为double类型的prvalue.该值保持不变

cppreference涵盖了C++中variadic函数的默认转换:

  • std :: nullptr_t转换为void*
  • float参数在浮点提升中转换为double
  • bool,char,short和unscoped枚举转换为int或更宽的整数类型,如整数提升

我们可以在C中看到并且可能在C++中看到这种转换是为了与K&R C保持一致,来自Rationale for International Standard-Programming Languages-C(强调我的):

为了与过去的实践兼容,所有参数促销都在K&R中描述,如果没有原型声明,包括并不总是希望将float加倍.

  • *是的,可变参数函数的浮点参数被提升为双精度。*仅在尾随参数中。请解决这个问题。 (2认同)

Cor*_*lks 16

至于问题的部分原因,很简单:C(和C++)标准被认为double是"默认"浮点类型.不是float(这是我们许多程序员在使用浮点数时默认的).

通过观察可以看出:

  1. 3.14是一个double(如果你想要一个float,你必须采取额外的步骤并附加一个f)
  2. 标准数学函数double默认sin()采用a (例如,取一个double;如果你想要一个float你必须使用sinf())

有了这个,似乎更"自然",一个float将被提升到double一个可变参数函数调用,因为double是在语言的"自然"的默认.

  • "不是`float`是我们许多程序员在使用浮点数时默认的." 我不知道别人怎么做,但我通常采取"双重".如果它是关于存储大量具有相当高的固有误差的测量数据而需要存储在文件中,我只求助于"浮动". (2认同)
  • 我对C的一大遗憾是,当添加`long double`时,没有包含任何机制来指定可变参数函数是否期望所有浮点值都转换为最长类型(`long double`),特定类型` double`,或者它预期`long double`和`double`以不同方式传递.恕我直言,如果代码可以说"将所有整数转换为这种类型并且所有东西都浮动到这种类型",那么多年来会节省很多时间和可移植性的麻烦. (2认同)

250*_*501 14

给定函数原型,只有在尾随参数中使用时,类型float才会自动提升1.功能打印使用:

int printf(const char * restrict format, ...);
Run Code Online (Sandbox Code Playgroud)

1(引用自:ISO/IEC 9899:201x 6.5.2.2函数调用)
6.对每个参数执行整数提升,并将类型为float的参数提升为double.这些被称为默认参数促销.
7.默认参数提升是在尾随参数上执行的.


Bas*_*tch 11

因为(C99或C11)标准是这样说的.见2501的回答.

有几个实用的原因:历史(C的第一个实现已用于系统编程,其中浮点运算无关紧要),以及在当前(平板电脑,台式机,服务器...)处理器,算术的事实操作double效率和效率一样高float(但是一些廉价的微控制器没有任何FPU,或者只能float通过硬件添加,并且每次操作都需要一个库double).最后,我想这样的规则可以实现稍微简单的调用约定ABI.

想想float作为一个排序的short double(这当然是非法的C).A float主要用于需要压缩内存(并且可以承受精度损失)时非常有用.有关更多信息,请参见http://floating-point-gui.de/.

  • C标准没有这样说.报价要么被错误引用,要么从该行错误的版本中获取. (2认同)