为什么printf()将浮点数提升为double?

从以前的问题来看:

如果你试图传递一个floatprintf ,它会在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 (这是我们很多程序员在使用浮点数时默认的)。

通过观察可以看出:

  1. 3.14是一个double (如果你想要一个float ,你必须采取额外的步骤,并附加一个f
  2. 标准的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/