为什么printf()将浮点数提升为double?
从以前的问题来看:
如果你试图传递一个
float
到printf
,它会在printf
收到之前被提升为double
printf()
是一个可变的函数吗? 那么一个可变参数在传递之前是否会提升float
参数呢?
是的,浮点参数可变函数被提升为double。
C99标准草案部分6.5.2.2
函数调用说:
[…]和floattypes的参数被提升为double。 这些被称为默认参数促销。[…]
来自C ++标准草案第5.2.2
节函数调用:
(4.6)的浮点types,参数的值在调用之前转换为升级types。 […]
和第4.6
节:
浮点types的前值可以转换为doubletypes的prvalue。 价值不变
cppreference包含C ++中可变参数的默认转换 :
- std :: nullptr_t被转换为void *
- 浮点参数转换为浮点提升中的双精度值
- bool,char,short和unscoped枚举被转换为int或更宽的整数types,如整数提升
我们可以在C中看到,大概是在C ++中,这个转换是为了与K&R C兼容的,从国际标准编程语言-C ( 我的重点 )的原理来看:
为了与过去的实践兼容,所有的参数促销发生在没有原型声明的情况下在K&R中所描述的, 包括并不总是期望的浮点数的双倍提升 。
至于问题的原因部分,很简单:C(和C ++)标准认为double
是“默认”浮点types。 不是float
(这是我们很多程序员在使用浮点数时默认的)。
通过观察可以看出:
-
3.14
是一个double
(如果你想要一个float
,你必须采取额外的步骤,并附加一个f
) - 标准的math函数默认为
double
(例如,sin()
需要一个double
;如果你想要一个float
你必须使用sinf()
)
有了这个,在一个可变的函数调用中, float
将被提升到double
,因为double
是语言中的“自然”默认值。
给定一个函数原型,只有当在尾随参数中使用floattypes时,才会自动提升1 。 function打印使用这些:
int printf(const char * restrict format, ...);
1 (引自:ISO / IEC 9899:201x 6.5.2.2函数调用)
6.对每个参数执行整数提升,并将floattypes的参数提升为double。 这些被称为默认参数促销。
7.默认参数促销是在结尾参数上执行的。
因为(C99或C11 )标准是这样说的。 请参阅2501的答案 。
有几个实际的原因:历史(C的第一个实现已经被用于系统编程,其中浮点运算不重要),以及在当前(平板电脑,台式机,服务器…)处理器,算术double
操作与float
操作一样高效(但是一些廉价的微控制器没有任何FPU,或者只能通过硬件增加float
,并且每个操作需要double
的库)。 最后,我想这样的规则可以使调用约定和ABI稍微简单一些。
将float
看作是一种short double
(在C中这当然是非法的)。 当你需要压缩内存时( float
可以承受精度的损失), float
是非常有用的。 有关更多信息,另见http://floating-point-gui.de/ 。