Correct format specifier for double in printf

"%f" is the (or at least one) correct format for a double. There is no format for a float, because if you attempt to pass a float to printf, it'll be promoted to double before printf receives it1. "%lf" is also acceptable under the current standard -- the l is specified as having no effect if followed by the f conversion specifier (among others).

Note that this is one place that printf format strings differ substantially from scanf (and fscanf, etc.) format strings. For output, you're passing a value, which will be promoted from float to double when passed as a variadic parameter. For input you're passing a pointer, which is not promoted, so you have to tell scanf whether you want to read a float or a double, so for scanf, %f means you want to read a float and %lf means you want to read a double (and, for what it's worth, for a long double, you use %Lf for either printf or scanf).


1. C99, §6.5.2.2/6: "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions." In C++ the wording is somewhat different (e.g., it doesn't use the word "prototype") but the effect is the same: all the variadic parameters undergo default promotions before they're received by the function.


Given the C99 standard (namely, the N1256 draft), the rules depend on the function kind: fprintf (printf, sprintf, ...) or scanf.

Here are relevant parts extracted:

Foreword

This second edition cancels and replaces the first edition, ISO/IEC 9899:1990, as amended and corrected by ISO/IEC 9899/COR1:1994, ISO/IEC 9899/AMD1:1995, and ISO/IEC 9899/COR2:1996. Major changes from the previous edition include:

  • %lf conversion specifier allowed in printf

7.19.6.1 The fprintf function

7 The length modifiers and their meanings are:

l (ell) Specifies that (...) has no effect on a following a, A, e, E, f, F, g, or G conversion specifier.

L Specifies that a following a, A, e, E, f, F, g, or G conversion specifier applies to a long double argument.

The same rules specified for fprintf apply for printf, sprintf and similar functions.

7.19.6.2 The fscanf function

11 The length modifiers and their meanings are:

l (ell) Specifies that (...) that a following a, A, e, E, f, F, g, or G conversion specifier applies to an argument with type pointer to double;

L Specifies that a following a, A, e, E, f, F, g, or G conversion specifier applies to an argument with type pointer to long double.

12 The conversion specifiers and their meanings are: a,e,f,g Matches an optionally signed floating-point number, (...)

14 The conversion specifiers A, E, F, G, and X are also valid and behave the same as, respectively, a, e, f, g, and x.

The long story short, for fprintf the following specifiers and corresponding types are specified:

  • %f -> double
  • %Lf -> long double.

and for fscanf it is:

  • %f -> float
  • %lf -> double
  • %Lf -> long double.