考证:关于printf的%f和%lf…

作者: yangzhe1991 分类: 我是搞技术的 发布时间: 2012-03-23 14:19 ė 61条评论

昨晚ACM-DIY群有一个人研究double的输出发现1099511627775.9998779296875这个数理论上是可以用双精度浮点表示的,但是实际printf输出的时候发现只能输出到1099511627775.9999000000,也就是只有18个有效数字。然后他怀疑是printf的问题。然后某人用cout试了下发现cout可以正常输出完整的浮点数……

然后发现,不同的编译器结果肯定是不一样的。printf都是错的,cout如果是比较新的gcc或对应的mingw就能正确输出,VS2010或旧版mingw都跟printf一样。当然一般情况下这类bug不会影响什么。所以也不考究这个了。

当时有人认为错误的原因是因为他用%f输出而那个人认为应该用%lf,当然也有人认为他可能是用%lf才导致这个错误应该用%f。于是这就是个老生常谈的问题了:printf的double到底用啥?当然scanf的float跟double不一样是肯定的。所以不考虑。对于printf用%lf还是%f输出double如今有三种观点:

————-

double 用%lf,float用%f

两者用哪个都行,标准里都有

两者用哪个都行是因为编译器自行认作相同,标准里其实只有%f没有%lf因此最合法的写法是%f哪怕%lf是对的

———–

之前我一直是第三种看法。因为在很多场合见到说标准里没有lf只有f。于是无聊,考证了下。

从历史角度讲,C语言有四个版本:

American National Standards Institute C,简称ANSI C,也叫C89;ISO采纳C89,变成ISO标准,叫C90,其实跟C89一样;C99;C11。

我今天才听说C11这东西(只听说新版cpp),在这里可以看出,ISO/IEC 9899:2011才是现行版本。于是找现行版本的材料,没找到免费的……突然想起某本书的作者曾经说,做标准这帮人想靠这个挣点钱于是不免费发布而是在网上卖,不知道现在还是不是……但是我搜到了一个貌似是表决稿或者叫C11讨论稿或者叫草案的东西,估计在printf这类问题上不会跟正式版有什么差异,于是用这个考证了下。

此pdf的前言部分,第15页Major changes in the second edition included中提到:

%lf conversion specifier allowed in printf

329页,fprintf函数的说明中提到(printf就是stdio的fprintf):

l (ell) Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument; that a following n conversion specifier applies to a pointer to a long int argument; that a following c conversion specifier applies to a wint_t argument; that a following s conversion specifier applies to a pointer to a wchar_t argument; or has no effect on a following a, A, e, E, f, F, g, or G conversion
specifier.

另外,这里说 the second edition是指C语言的第二版,也就是C99.换句话说这个特性是从C99开始有的。

总之就是一句话:

%f和%lf都对,也都是符合C标准的写法。

本文出自 杨肉的演讲台,转载时请注明出处及相应链接。

本文永久链接: https://yangzhe1991.org/blog/2012/03/printf-f-lf/

0

一条评论

  1. cot 2012 年 4 月 27 日 17:28 回复
    Unknown Unknown Unknown Unknown

    很佩服作者的考证精神。
    请问,是不是可以这样理解:应该把C/C++编译器更新到最新版本,然后就可以随便搞了?

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Ɣ回顶部