I'm trying to learn C by reading C Programming Language, 2nd Edition . I have some programming experience but not with C.
I'm currently in Chapter 1. I have the following code:
float f;
for (f = 0.0; f <= 3; f += 1.1)
printf("A: %3f B: %6.2f\n", f, f + 0.15);
It prints the output:
A: 0.000000 B: 0.15
A: 1.100000 B: 1.25
A: 2.200000 B: 2.35
Looks fine.
Now I change the printf as follows:
printf("A: %3d B: %6.2f\n", f, f + 0.15);
The new output is
A: 0 B: 0.00
A: -1610612736 B: 0.00
A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00
What's going on here? I would expect the float to be converted to int because I used %d but that's not what happened. Also, why did the the value B go wrong as well? What happened to f here?
No. The d stands for “decimal”, and a %d format requires an argument of type int . There are several formats for type double : %f , %e , %g . You can use %lf , but the l is quietly ignored (this was added in the 1999 standard for symmetry with scanf , which has to distinguish between float and double ).
Let's see an example of taking and displaying a float , a double and a char value. So, you can see here that %d is used for integers, %f for floats and %c for characters.
%s refers to a string %d refers to an integer %c refers to a character. Therefore: %s%d%s%c\n prints the string "The first character in sting ", %d prints i, %s prints " is ", and %c prints str[0].
%d stands for decimal and it expects an argument of type int (or some smaller signed integer type that then gets promoted). Floating-point types float and double both get passed the same way (promoted to double ) and both of them use %f .
When you called:
printf("A: %3d B: %6.2f\n", f, f + 0.15);
C automatically converts the float
values to double
(it is a standard conversion made when you call a function that takes variable arguments, such as int printf(const char *fmt, ...);
). For sake of argument, we will assume that sizeof(int)
is 4 and sizeof(double)
is 8 (there are exceptions, but they are few and far between).
The call, therefore, has pushed a pointer onto the stack, plus an 8-byte double for f
, and another 8-byte double for f + 0.15
. When it is processing the format string, the %d
tells printf()
that you pushed a 4-byte int
onto the stack after the format string. Since that is not what you did, you have invoked undefined behaviour; whatever happens next is OK according to the C standard.
However, the most likely implementation blithely reads 4 bytes and prints them as if they were an int
(it trusts you to tell it the truth). Then it comes across the %6.2f
format; it will read 8-bytes off the stack as a double
. There's an outside chance that this would cause a memory fault for misaligned access (it would require a 64-bit machine with a requirement that double
be aligned on an 8-byte boundary, such as a SPARC), or it will read 4 bytes from f
and 4 bytes from f + 0.15
, putting them together to create some rather unexpected double
value -- as your example shows.
Printf will treat the memory you point as however you tell it to. There is no conversion going on. It is treating the memory that represents the float as an int. Because the two are stored differently, you get what is essentially a random number.
If you want to output your float as an integer, you should cast it first:
printf("A: %3d B: %6.2f\n", (int)f, f + 0.15);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With