来自之前的一个问题:
如果您尝试将
float
传递给printf
,则在printf
接收到它之前,它将被提升为double
printf()
是可变参数函数吗?因此,可变参数函数会在将float
参数传递给printf
之前将其提升为double
吗?
来自之前的一个问题:
如果您尝试将
float
传递给printf
,则在printf
接收到它之前,它将被提升为double
printf()
是可变参数函数吗?因此,可变参数函数会在将float
参数传递给printf
之前将其提升为double
吗?
cppreference很好地涵盖了C++可变参数函数的default conversions:
- std::nullptr_t会转换为void*
- 浮点参数会像浮点数提升一样转换为double
- bool、char、short和未作用域枚举会像整数提升一样转换为int或更宽的整数类型
我们可以看到在C中,也许在C++中,这种转换是为了与K&R C兼容而保留下来的,来自Rationale for International Standard—Programming Languages—C(我强调):
为了与过去的实践相兼容,在没有原型声明的情况下,所有参数的提升都按照K&R中描述的方式进行,包括不总是理想的将float提升为double。
double
视为“默认”浮点类型。不是float
(当我们使用浮点数时,许多程序员会将其作为默认值)。3.14
是一个double
(如果你想要一个float
,你需要额外添加一个f
)double
(例如sin()
采用double
;如果你想使用float
,你需要使用sinf()
)。float
提升为double
,因为double
是该语言中的“自然”默认值。long double
被添加进去时,没有包括任何机制来指定可变参数函数是否期望将所有浮点数值转换为最长类型 (long double
)、特定类型 double
或者期望 long double
和 double
被传递不同。依我看,如果代码可以说“将所有整数状的东西都转换为这种类型,所有浮点状的东西都转换为那种类型”,那么多年来会节省很多时间和可移植性上的问题。 - supercat给定一个函数原型,当使用尾部参数时,类型为浮点数的自动提升1。函数print使用它们:
int printf(const char * restrict format, ...);
1(摘自:ISO/IEC 9899:201x 6.5.2.2 函数调用)
6. 对每个参数执行整数提升,具有 float 类型的参数被提升为 double。这些称为默认参数提升。
7. 默认参数提升在尾部参数上执行。
因为(C99或C11)标准规定了这样做。请参见2501的回答。
有几个实用的原因:历史(最早的C实现被用于系统编程,浮点运算并不重要),以及在当前(平板电脑,桌面,服务器...)处理器上,double
的算术运算与float
相比大约同样有效(但一些廉价的微控制器没有FPU,或者只能通过硬件添加float
,并且需要为每个double
操作使用库)。最后,我想这样的规则使得稍微简单一些的调用约定和ABI。
将float
视为一种类似于short double
的东西(当然,在C中这是非法的)。float
主要在您需要紧凑存储器(并且可以承受精度损失)时才有用。另请参见http://floating-point-gui.de/获取更多信息。
char
被提升为int
,所以char c=127; printf("%d", c);
也能正确工作。 - Weather Vanefloat
值并不总是被转换为double
,但是当作为可变参数函数(如printf
)的尾随参数传递时,它们会被转换为double
。 - davmac