为什么 printf() 将浮点数提升为双精度数?

Why does printf() promote a float to a double?

来自之前的question

If you attempt to pass a float to printf, it'll be promoted to double before printf receives it

printf() 是可变参数函数吗?那么可变参数函数是否会在传递之前将 float 参数提升为 double

是的,可变参数函数的浮点参数被提升为双精度。

draft C99 standard 部分 6.5.2.2 函数调用说:

[...]and arguments that have type float are promoted to double. These are called the default argument promotions.[...]

来自 draft C++ standard 部分 5.2.2 函数调用:

[...]a floating point type that is subject to the floating point promotion (4.6), the value of the argument is converted to the promoted type before the call. [...]

和第 4.6 部分:

A prvalue of type float can be converted to a prvalue of type double. The value is unchanged

cppreference covers the default conversions 用于 C++ 中的可变参数函数:

  • std::nullptr_t is converted to void*
  • float arguments are converted to double as in floating-point promotion
  • bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion

我们可以在 C 中看到,并且大概在 C++ 中,为了与 K&R C 兼容,我们可以看到这种转换,来自 Rationale for International Standard—Programming Languages—C强调我的):

For compatibility with past practice, all argument promotions occur as described in K&R in the absence of a prototype declaration, including the not always desirable promotion of float to double.

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

这个可以通过观察看出:

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

有了这个,似乎 "natural" 在可变函数调用中 float 将被提升为 double,因为 double 是 "natural" 语言默认。

因为 (C99 或 C11) standard says so. See .

这有几个实用的原因:历史(C 的第一个实现已用于系统编程,其中浮点运算无关紧要),以及当前(平板电脑、台式机、服务器.. .) 处理器,double 上的算术运算与 float 的效率差不多(但一些廉价的微控制器没有任何 FPU,或者只能通过硬件添加 float,并且需要一个库对于 double 上的每个操作)。最后,我想这样的规则可以使 calling conventions and ABIs.

稍微简单一些

float 视为一种 short double(在 C 中当然是 非法 )。 float 主要用于需要压缩内存(并且可以承受精度损失)的情况。另请参阅 http://floating-point-gui.de/ 了解更多信息。

给定函数原型,浮点型仅在用于尾随参数时自动提升1。函数打印使用那些:

int printf(const char * restrict format, ...);

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