为什么 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
(这是我们许多程序员在使用浮点数时的默认设置)。
这个可以通过观察看出:
3.14
是一个 double
(如果你想要一个 float
,你必须采取额外的步骤并附加一个 f
)
- 标准数学函数默认采用
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.默认参数
对尾随参数执行促销。
来自之前的question:
If you attempt to pass a
float
toprintf
, it'll be promoted todouble
beforeprintf
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
(这是我们许多程序员在使用浮点数时的默认设置)。
这个可以通过观察看出:
3.14
是一个double
(如果你想要一个float
,你必须采取额外的步骤并附加一个f
)- 标准数学函数默认采用
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.默认参数
对尾随参数执行促销。