Meaning of "%lf" place holder - c

Here is my small program where I intently put the place holder %lf in the second printf. Why the second printf has the same result as the first printf( both printf 1.3).
int main()
{
double f = 1.3;
long l = 1024L;
printf("f = %lf", f);
printf("l = %lf", l);
return 0;
}

It's Undefined behaviour if printf() has format specifier mismatch. %lf expects a double but you are passing a long int.
C11, 7.21.6.1 The fprintf function
9 If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
That said, what probably happens is that when you call printf() the first time, the value of f is passed in a floating point register or at a location in stack for double. The next time you call printf(), it reads from the same location due to the format specifier %lf. As opposed to reading from where the value of l is stored. If you swap the order of printf() calls, you would probably observe a different output. But this is all platform specific. Once your program invokes undefined behaviour, anything can happen. Basically, you can't expect it to do anything sensible and there is absolutely no guarantee about its behaviour.

Here if you change your code to this:
#include <stdio.h>
int main()
{
double f = 1.3;
long l = 1024L;
printf("f = %lf", f);
printf("l = %lf", (float)l);
return 0;
}
you will see that the output would be different. When you pass a long to be presented as double you should expect undefined behavior

You have a specifier mismatch. The value
long l = 1024L;
is interpreted as a double; and this happens to be approximately 1.3 (at least on your and my pc. This might be different on different architectures I think; depending on how long a "long" and a "double" are, and how they are represented internally.
As for the meaning of the %lf placeholder, you can see in the printf documentation that %f means: decimal floating point. the l length modifier has no influence on the %f specifier.
Conclusion: %lf = %f = decimal floating point

Related

difference between %fl and %lf in C

I am currently learning about C language data type and I try to print a double variable the compiler suggested me to use fl after I type '%', and I got 1 number in the end of precision decimal line. Compare to %lf it will print six precision decimals in total
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.0000001
I've searched plenty of place but mostly the difference between %f and %lf is frequently asked. Is my situation could possiply the same?
In this call of printf
printf("%lf",num);// result is 12322.000000
the length modifier l in the conversion specifier %lf has no effect.
From the C Standard (7.21.6.1 The fprintf function)
7 The length modifiers and their meanings are:
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.
In this call of printf
printf("%fl",num);// result is 12322.0000001
where in the comment there shall be written the letter 'l' instead of the number 1 as you think
// result is 12322.000000l
^^^
the format string "%fl" means that after outputting an object of the type double due to the conversion specification %f there will be outputted the letter 'l'.
Pay attention to that with the conversion specifier f there can be used one more letter 'l' that is the upper case letter 'L'. In this case the conversion specification %Lf serves to output objects of the type long double.
I think you actually have a typo in your output....
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.0000001
is actually
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.000000l
The C standard says that the float is converted to a double when passed to a variadic function, so %lf and %f are equivalent; %fl is the same a %f... with an l after it.
There are two correct ways of printing a value of type double:
printf("%f", num);
or
printf("%lf", num);
These two have exactly the same effect. In this case, the "l" modifier is effectively ignored.
The reason they have the same effect is that printf is special. printf accepts a variable number of arguments, and for such functions, C always applies the default argument promotions. This means that all integer types smaller than int are promoted to int, and float is promoted to double. So if you write
float f = 1.5;
printf("%f\n", f);
then f is promoted to double before being passed. So inside printf, it always gets a double. So %f will never see a float, always a double. So %f is written to expect a double, so it ends up working for both float and double. So you don't need a l modifier to say which. But that's kind of confusing, so the Standard says you can put the l there if you want to — but you don't have to, and it doesn't do anything.
(This is all very different, by the way, from scanf, where %f and %lf are totally different, and must be explicitly matched to arguments of type float * versus double *.)
I have no idea why your IDE complained about (put a red line under) %lf, and I have no idea what it meant by suggesting, as you said,
fl, lg, l, f,
elf, Alf, ls, sf,
if, la, lo, of
Some of those look they might be nonstandard, system-specific extensions, but some (especially fl) are nonsense. So, bottom line, it sounds like your IDE's suggestion was confusing, unnecessary, and quite possibly wrong.

Why format specifier %d or %i does not work for a double variable but %f works and print a float output of an integer variable?

Must we always use %f to printf a %d value, and %lf to take input by scanf ? Why format specifier %d or %i does not work for a double variable but %f works and print a float output of an integer variable?
Is it always safe to declare double and take input scanf with %lf and printf as %f?
My codes:
int main(void)
{
double dnum = 7777;
printf(" %f \n", dnum);
return 0;
}
output is 7777.000000
int main(void)
{
double dnum = 7777;
printf(" %i \n", dnum);
return 0;
}
Output is 0
int main(void)
{
double dnum = 7777;
printf(" %d \n", dnum);
return 0;
}
Output is 0
Format and data mismatch in printf() invokes undefine behavior.
In your code, the type of dnum is double regardless of its actual value, which may be an integer.
%f can be used to print double, but neithor %d nor %i cannot be used.
If you want to print double, you should use %g, %f or %e depending on the format that you want it to be printed.
%d is the same as %i (for printf) and it goes along with signed integer.
The format specifier: %d or %i expects the argument of signed int, if anything else is given in the formatted printf() statement, such as:
float f = 1.50235F;
printf("%d", f);
Will expect for signed int, if you pass a float or a double instead, it'll tend to undefined behavior and probably print 0.
In a more practical sense, if you want to do-it-yourself, you may add -Wformat flag and run the command in your command prompt or any command shell:
$ gcc -o main main.cpp -Wformat
Then you'll get a warning generated by the compiler similar to the following:
main.c: In function 'int main()':
main.c:9:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=]
9 | printf("%d\n", d);
| ~^ ~
| | |
| int double
| %f
The double has the twice precision than a float could hold (i.e. double has 15 decimal digits of precision, while float has only 7. So, the %f type specifier could be used for double in this case too.)
To know further about the format specifiers: List of all format specifiers in C.
All conversion specifiers expect their corresponding argument to be a specific type; you can't arbitrarily mix and match them. %d and %i expect their corresponding argument to have type int - if it doesn't, the behavior is undefined and you'll (usually) get weird output. Integers and floating point values have very different binary representations and may have different sizes - most modern platforms use 32 bits to store integer values and 64 bits to store doubles, which affects how those values are interpreted in the printf code.
For an authoritative list of conversion specifiers and the types of arguments they take, refer to the C 2011 Online Draft, section 7.21.6.1 (The fprintf function).
Welcome in the world of undefined behavior!
To use the %d conversion specifier to print a double value or the %f conversion specifier to print an int value invokes undefined behavior.
%f is furthermore meant to print a value of type double, not float. A passed float gets automatically promoted.
The C standard states:
If a conversion specification is invalid, the behavior is undefined.288) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Source: C18, 7.21.6.1/9
d,i - The int argument is converted to signed decimal in the style[-]dddd. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it is expanded with leading zeros. The default precision is 1. The result of converting a zero value with a precision of zero is no characters.
......
f,F - A double argument representing a floating-point number is converted to decimal notation in the style[-]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is zero and the flag is not specified, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.
A double argument representing an infinity is converted in one of the styles[-]infor[-]infinity— which style is implementation-defined. A double argument representing a NaN is converted in one of the styles[-]nanor[-]nan(n-char-sequence)— which style, and the meaning of any n-char-sequence, is implementation-defined. The F conversion specifier produces INF,INFINITY, or NAN instead of inf, infinity, or nan, respectively.283)
Source: C18, §7.21.6.1/8
Summary:
Except for the first example, The output you get is any arbitrary value (unless the implementation didn't specified what happens else). It doesn't "work" in the one way nor in the other.

Printing the result of operations on integers and floats

Consider the following C-program:
int main() {
int a =2;
float b = 2;
float c = 3;
int d = 3;
printf("%d %f %d %f %d %f %d %f\n", a/c, a/c, a/d, a/d, b/c, b/c, b/d, b/d);
printf("%d\n", a/c);
}
The output of this is:
0 0.666667 0 0.666667 2 0.666667 0 0.666667
539648
I can't make sense of this at all. Why does printing a/c as an integer give 0, while b/c gives 2? Aren't all integers promoted to floats in computations involving both floats and integers? So the answer should be 0 in both cases.
In the second line of the output I'm simply printing a/c as an integer, which gives a garbage value for some reason (even though it gives 0 when I print it in the first compound printf statement). Why is this happening?
You have undefined behaviour:
printf("%d %f %d %f %d %f %d %f\n", a/c, a/c, a/d, a/d, b/c, b/c, b/d, b/d);
The format specifier for printf must match the type of the provided parameter. As printf doesn't provide a parameter list with types, but only ... there is no implicit type conversion apart from standard type conversion.
If you have UB, basically anything can happen.
What is likely to happen is the following:
Depending on the format specifier, printf consumes a certain number of bytes from the calling parameters. This number of bytes matches the specified format type. If the number of bytes does not match the number of bytes passed as an argument, you are out of sync for all successive parameters.
And of course you do incorrect interpretation of the data.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
If you have for example the following declarations
int a =2;
float c = 3;
and then call the function printf the following way
printf( "%d", a / c );
then behind the hood the following events occur.
The expression a / c has the type float due to the usual arithmetic conversions.
As the function printf is declared with the ellipsis notation then to the expression a / c of the type float there are applied the default argument promotions that convert the expression to the type double.
As result in this call there is an attempt to output an expression of the type double using conversion specifier %d designed for the type int. Hanse the call has undefined behavior.
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.

Different output every time in c?

I am trying to learn C and am very confused already.
#include <stdio.h>
int main(void)
{
int a = 50000;
float b = 'a';
printf("b = %f\n", 'a');
printf("a = %f\n", a);
return 0;
}
The above code produces a different output each time with gcc. Why?
You pass an int value ('a') for a %f format expecting a float or a double. This is undefined behavior, which can result in different output for every execution of the same program. The second printf has the same problem: %f expects a float or double but you pass an int value.
Here is a corrected version:
#include <stdio.h>
int main(void) {
int a = 50000;
float b = 'a';
printf("a = %d\n", a);
printf("b = %f\n", b);
printf("'a' = %d\n", 'a');
return 0;
}
Output:
a = 50000
b = 97.000000
'a' = 97
Compiling with more warnings enabled, with command line arguments -Wall -W -Wextra lets the compiler perform more consistency checks and complain about potential programming errors. It would have detected the errors in the posted code.
Indeed clang still complains about the above correction:
clang -O2 -std=c11 -Weverything fmt.c -o fmt
fmt.c:8:24: warning: implicit conversion increases floating-point precision: 'float' to 'double' [-Wdouble-promotion]
printf("b = %f\n", b);
~~~~~~ ^
1 warning generated.
b is promoted to double when passed to printf(). The double type has more precision than the float type, which might output misleading values if more decimals are requested than the original type afforded.
It is advisable to always use double for floating point calculations and reserve the float type for very specific cases where it is better suited, such as computer graphics APIs, some binary interchange formats...
From implementation standpoint, passing floating point numbers (that what %f expects) as variable argument lists (that is what ... means in printf prototype) and integers (that is what 'a' is, specifically of type int) may use different registers and memory layout.
This is usually defined by ABI calling conventions. Specifically, in x86_64, %xmm0 will be read by printf (with unitialized value), but gcc will fill %rdi in printf call.
See more in System V Application Binary Interface AMD64 Architecture Processor Supplement, p. 56
You should note that C is a very low-level language which puts a lot of confusing cases (including integer overflows and underflows, unitialized variables, buffer overruns) on shoulders of implementation. That allows to gain maximum performance (by avoiding lots of checks), but leaves to errors such as this error.
The %f specifier needs to be matched by a floating-point parameter (float or double), you're giving it ints instead. Not matching the type is undefined behaviour, meaning it could do anything, including printing different results everytime.
Hope this helped, good luck :)
Edit: Thanks chqrlie for the clarifications!
Unpredictable behavior.
When you try to print value using mismatch format specifier, compiler give an unpredictable output.The behavior on using %f as the format specifier for an char and int is undefined.
Use correct format specifier in your program according yo data type:
printf("%d\n", 'a'); // print ASCII value
printf("%d\n", a);
First of all, gcc should give a warning for the above code. This is because of the mismatch in the format specifier.
Mismatched formatting (printf() as well as scanf()) will give unpredictable behavior in C. This is in spite of the fact that gcc is expected to take care possible type conversions like int to float implicitly.
Here is are two nice references.
https://stackoverflow.com/a/1057173/4954434
https://stackoverflow.com/a/12830110/4954434
Following will work as expetced.
#include <stdio.h>
int main(void)
{
int a = 50000;
float b = 'a';
printf("b = %f\n", (float)'a');
printf("a = %f\n", (float)a);
return 0;
}
The main difficult you are having is the data type you are using.
When you create a variable you are telling the size the memory will have to reserve to work properly. Like char have a size of 1 byte, int equal 4 byte and float 32 byte. It's important to use the same data type to not have unpredictable result.
char a = 'a';
printf("%c",a);
int b = 50000;
printf("%d",b);
float c = 5.7;
printf("%f", c);
For more information: C-Variables

printf output for cross format specifier

The below program is printing 123828749, 0.000000 but I expected 123828749, 123828749.0. From where it is getting 0.000000 ?
#include <stdio.h>
void main()
{
double x = 123828749.66;
int y = x;
printf("%d\n", y);
printf("%lf\n", y);
}
Thanks
In the second call to printf you are passing an int, but the format string is %lf which expects a floating point value to be passed. This invokes undefined behaviour.
If you want to treat y as a floating point value when you pass it to printf, you'll need an explicit conversion:
printf("%lf\n", (double)y);
To answer more precisely to your question (even though David's answer is completely precise), when (at runtime) the format string gets parsed by printf function it expects double format. However, you supplied an int and since int is most likely not the same size as double (there is no indication that this is the case, though) your program read some junk memory and printed this unexpected result. This is where the zeroes came from.

Resources