为什么不是`printf`中定义的`float`的说明符?

时间:2015-09-11 07:29:46

标签: c floating-point printf rationale c-standard-library

看起来可能已经存在(至少在C99中)长度修饰符可以应用于int%hhd%hd%ld%lld表示signed charshortlonglong long。甚至还有适用于double的长度修饰符:%Lf表示long double

问题是为什么他们忽略了float?遵循该模式,它可能是%hf

4 个答案:

答案 0 :(得分:47)

因为在C变量函数调用中,任何float参数都被提升(即转换)为double,因此printf获得double并使用{{ 1}}让它在其实现中。

过去(C89和K& R C),每个va_arg(arglist, double)参数都转换为float。当前标准省略了针对具有明确原型的固定arity函数的此促销。它与ABI&有关(并详细说明)。 calling conventions实施。实际上,当作为参数传递时,double值通常会被加载到双浮点寄存器中,但细节可能会有所不同。以Linux x86-64 ABI specification为例。

此外,没有实际的理由为float提供特定的格式控制字符串,因为您可以根据需要调整输出的宽度(例如,使用float),%8.5f%hd中比在scanf

中更有用(几乎是必要的)

除此之外,我想原因(省略printf指定%hf - 在调用者float中促进double 是历史性的:首先,C是一种系统编程语言,而不是HPC语言(Fortran在HPC中是首选,直到20世纪90年代后期)并且printf不是很重要;它(并且仍然)被认为是float,一种降低内存消耗的方法。今天的FPU足够快(在台式机或服务器计算机上)以避免使用short,除非作为使用更少内存的手段。你基本上应该相信每个float都在某个地方(可能 FPU或CPU中)转换为float

实际上,您的问题可能会被解释为:为double存在%hd的原因(它基本上没用,因为printf在您通过printf时会获得int一些short;但是scanf需要它!)。我不知道为什么,但我想,比系统编程更有用。

您可以花时间游说下一个ISO C标准,%hfprintf接受float doubleprintf short来电{}} int - s被提升为float),当双精度值超出%hf - s的范围时,未定义的行为,以及{{1}接受的对称scanf对于float指针。祝你好运。

答案 1 :(得分:2)

考虑到scanf有浮动,双重或双倍的单独格式说明符,我不明白为什么printf和类似的功能没有以类似的方式实现,但是这就是C / C ++和标准的结果。

根据处理器和当前模式,推送或弹出操作的最小大小可能存在问题,但这可能是使用默认填充处理的,类似于局部变量或结构中的变量的默认对齐。当它从16位编译到32/64位编译器时,微软放弃了对80位(10字节)long double的支持,现在将long doubledouble s相同(64位/ 8字节)。他们可以根据需要将它们填充到12或16字节边界,但这还没有完成。

答案 2 :(得分:2)

当C被发明时,所有浮点值在用于计算或传递给函数(包括)double之前都被转换为公共类型(即printf),因此没有必要for printf在浮点类型之间做出任何区分。

为了提高算术效率和准确性,IEEE-754浮点标准定义了一个80位类型,它比普通的64位double大,但可以更快地处理。意图是给定像a=b+c+d;这样的表达式,将所有内容转换为80位类型,将三个80位数字相加,并将结果转换为64位类型,将更快更准确而不是将总和(b+c)计算为64位类型,然后将其添加到d

为了支持新类型,ANSI C定义了一种新类型long double,其实现可以引用新的80位类型或64位double。不幸的是,即使IEEE-754 80位类型的目的要使所有值按照它们被提升为double的方式自动升级到新类型,ANSI也是如此新类型传递给printf或其他可变方法与其他浮点类型不同,从而使这种自动提升无法维持。

因此,创建C时存在的两种浮点类型都可以使用相同的%f格式说明符,但之后创建的long double需要不同的%Lf格式说明符(使用大写 L)。

答案 3 :(得分:2)

%hhd%hd%ld%lld已添加到printf,以使格式字符串与scanf更加一致,即使由于默认参数促销,它们对于printf来说是多余的。

那么为什么%hf没有添加float?这很简单:查看scanf的行为,float已经有了格式说明符。它是%fdouble的格式说明符为%lf

%lf正是C99添加到printf的内容。在C99之前,%lf的行为未定义(通过省略标准中的任何定义)。从C99开始,它是%f的同义词。