I have seen these two parameters in a C example in a C book, but the author didn't elaborate what the difference between the two is. I know that %f
specifies that a float
should take its place. I have tried looking this up but have had a hard time finding an explanation. What about %lf
?
The short answer is that it has no impact on printf
, and denotes use of float
or double
in scanf
.
For printf
, arguments of type float
are promoted to double
so both %f
and %lf
are used for double
. For scanf
, you should use %f
for float
and %lf
for double
.
More detail for the language lawyers among us below:
There is no difference between %f
and %lf
in the printf
family. The ISO C standard (all references within are from C11), section 7.21.6.1 The fprintf function
, paragraph /7
states, for the l
modifier (my emphasis):
Specifies that a following
d
,i
,o
,u
,x
, orX
conversion specifier applies to along int
orunsigned long int
argument; that a followingn
conversion specifier applies to a pointer to along int
argument; that a followingc
conversion specifier applies to awint_t
argument; that a followings
conversion specifier applies to a pointer to awchar_t
argument; or has no effect on a followinga
,A
,e
,E
,f
,F
,g
, orG
conversion specifier.
The reason it doesn't need to modify the f
specifier is because that specifier already denotes a double
, from paragraph /8
of that same section where it lists the type for the %f
specifier:
A
double
argument representing a floating-point number is converted to decimal notation
That has to do with the fact that arguments following the ellipse in the function prototype are subject to default argument promotions as per section 6.5.2.2 Function calls
, paragraph /7
:
The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.
Since printf
(and the entire family of printf
-like functions) is declared as int printf(const char * restrict format, ...);
with the ellipsis notation, that rule applies here. The default argument promotions are covered in section 6.5.2.2 Function calls
, paragraph /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 todouble
. These are called the default argument promotions.
For the scanf
family, it mandates the use of a double
rather than a float
. Section 7.21.6.2 The fscanf function /11
:
Specifies that a following
d
,i
,o
,u
,x
,X
, orn
conversion specifier applies to an argument with type pointer tolong int
orunsigned long int
; that a followinga
,A
,e
,E
,f
,F
,g
, orG
conversion specifier applies to an argument with type pointer todouble
; or that a followingc
,s
, or[
conversion specifier applies to an argument with type pointer towchar_t
.
This modifies the /12
paragraph of that section that states, for %f
:
Matches an optionally signed floating-point number, infinity, or
NaN
, whose format is the same as expected for the subject sequence of thestrtod
function. The corresponding argument shall be a pointer to floating.
The reason why the default argument promotions don't come into play for scanf
is because you're not actually passing a float
that would be converted (or you shouldn't be). Instead, you're meant to pass a pointer to a float which is not affected by those promotions.
The printf
family takes values because it just needs to use them. The scanf
family needs pointers to the values because its intent is to change those values, hence needs to know where to write the new values (C is strictly pass-by-value: pass-by-reference is emulated by using pointers and dereferencing).
For scanf
, %f
reads into a float
, and %lf
reads into a double
.
For printf
: In C99 and later, they both are identical, and they print either a float
or a double
. In C89, %lf
caused undefined behaviour although it was a common extension to treat it as %f
.
The reason that one specifier can be used for two different types in printf
is because of the default argument promotions; arguments of type float
are promoted to double
when used to call a function and not matching a parameter in a function prototype. So printf
just sees a double
in either case.
For output using the printf family of functions, the %f and %lf specifiers mean the same thing; the l is ignored. Both require a corresponding argument of type double — but an argument of type float is promoted to double, which is why there’s no separate specifier for type float. (This promotion applies only to variadic functions like printf and to functions declared without a prototype, not to function calls in general.) For type long double, the correct format specifier is %Lf.
For input using the scanf family of functions, the floating-point format specifiers are %f, %lf, and %Lf. These require pointers to objects of type float, double, and long double, respectively. (There’s no float-to-double promotion because the arguments are pointers. A float value can be promoted to double, but a float* pointer can’t be promoted to a double* because the pointer has to point to an actual float object.)
But be careful using the scanf functions with numeric input. There is no defined overflow checking, and if the input is outside the range of the type your program’s behavior is undefined. For safety, read input into a string and then use something like strtod to convert it to a numeric value. (See the documentation to find out how to detect errors.)
The width modifier in %lf is gracefully ignored by printf(). Or, to be more accurate, %f takes a double - varargs will always promote float arguments to double.
© 2022 - 2024 — McMap. All rights reserved.
%f
and%lf
, did you try looking upprintf
orfprintf
? – Hangoverprintf
(and family) reference handy. Of course there's also a reference forscanf
(and family). – Lilas