27 c c++ floating-point printf variadic-functions
从上一个问题:
如果你试图传递
float
给printf
它,它会double
在printf
收到它之前被提升
printf()
是一个可变函数吧?可变参数函数在传递之前是否会提升float
参数double
?
Sha*_*our 26
是的,variadic函数的float参数被提升为double.
在C99标准草案部分6.5.2.2
函数调用说:
[...]并且类型为float的参数被提升为double.这些被称为默认参数促销.[...]
从草案C++标准部分5.2.2
函数调用:
[...]浮点类型受浮点提升(4.6)影响,参数值在调用之前转换为提升类型.[...]
和部分4.6
:
float类型的prvalue可以转换为double类型的prvalue.该值保持不变
cppreference涵盖了C++中variadic函数的默认转换:
- std :: nullptr_t转换为void*
- float参数在浮点提升中转换为double
- bool,char,short和unscoped枚举转换为int或更宽的整数类型,如整数提升
我们可以在C中看到并且可能在C++中看到这种转换是为了与K&R C保持一致,来自Rationale for International Standard-Programming Languages-C(强调我的):
为了与过去的实践兼容,所有参数促销都在K&R中描述,如果没有原型声明,包括并不总是希望将float加倍.
Cor*_*lks 16
至于问题的部分原因,很简单:C(和C++)标准被认为double
是"默认"浮点类型.不是float
(这是我们许多程序员在使用浮点数时默认的).
通过观察可以看出:
3.14
是一个double
(如果你想要一个float
,你必须采取额外的步骤并附加一个f
)double
默认sin()
采用a (例如,取一个double
;如果你想要一个float
你必须使用sinf()
)有了这个,似乎更"自然",一个float
将被提升到double
一个可变参数函数调用,因为double
是在语言的"自然"的默认.
250*_*501 14
给定函数原型,只有在尾随参数中使用时,类型float才会自动提升1.功能打印使用:
int printf(const char * restrict format, ...);
Run Code Online (Sandbox Code Playgroud)
1(引用自:ISO/IEC 9899:201x 6.5.2.2函数调用)
6.对每个参数执行整数提升,并将类型为float的参数提升为double.这些被称为默认参数促销.
7.默认参数提升是在尾随参数上执行的.
Bas*_*tch 11
有几个实用的原因:历史(C的第一个实现已用于系统编程,其中浮点运算无关紧要),以及在当前(平板电脑,台式机,服务器...)处理器,算术的事实操作double
效率和效率一样高float
(但是一些廉价的微控制器没有任何FPU,或者只能float
通过硬件添加,并且每次操作都需要一个库double
).最后,我想这样的规则可以实现稍微简单的调用约定和ABI.
想想float
作为一个排序的short double
(这当然是非法的C).A float
主要用于需要压缩内存(并且可以承受精度损失)时非常有用.有关更多信息,请参见http://floating-point-gui.de/.