Reputation: 23
int main(void)
{
int a = 65;
char c = (char)a;
printf("%c\n", c); // output: A
printf("%f\n", (float)a); // output: 65.000000
printf("%f\n", 5/2); // output: 65.000000 why???
return 0;
}
//why printf("%f\n", 5/2); prints same number as a number above????
it supposed to print 2.5, i want to know why it doesn't prints this number and what's happens bts? i tried to find answers on google but i'm not sure how to question this problem
Upvotes: 1
Views: 463
Reputation: 113
The behaviour is due to the way arguments are passed to functions.
For e.g., integer values are passed via registers like edx, esi etc. (as long as the arguments fit in available registers). However, floating point arguments are passed in xmm* registers (as long as they fit in available registers).
So inside the function, the values are fetched from appropriate registers based on the type specifier. So a %d
would fetch from edx
/esi
etc, and %f
would fetch from xmm*
registers.
In your case, the line printf("%f\n", (float)a);
stored the value of a
(which is 65) as a real value 65.0
due to typecasting. As a result, xxm0
register will have value 65.0.
Now when the control came to printf("%f\n", 5/2);
, the function argument 5/2
is an integer. So it doesn't get pushed into xxm0
register. However since %f
expects a value in xxm*
(in this case xxm0
) register, it just retries whatever value is there in xxm0. In your case, xxm0
had stored the value 65.0 from earlier printf()
call. So 65.0 is printed.
The below program should make it more clear:
int main(void)
{
printf("%f\n", 10, 11.1, 12.2, 40); // 11.100000
printf("%f %f\n", 5/2, 1, 2, 3, 4); // 11.100000 12.200000
}
During first printf()
call, xxm0 = 11.1
and xxm1 = 12.2
. Since all of the arguments in the second printf()
evaluate to be integers, so nothing gets stored in xxm*
registers (which also means old values of xxm*
registers remain unaltered). Since %f
expects real numbers to be in xxm*
registers, it just prints whatever values they hold (in this case values from first printf()
statement).
You can use https://www.godbolt.org to see the generated assembly code.
Upvotes: 0
Reputation: 48052
This is a simplified and not necessarily perfectly accurate answer, but: When you use %f
in a printf
format statement, it does not mean "take the next argument that was passed, and print it as a float". No, instead what it means is "take the next float argument that was passed, and print it." But in your third printf
call, there was no float argument that was passed (because 5/2
gives the int
value 2). So when printf
went to look in the place where float arguments are passed, by chance it picked up the last actual floating-point number you had passed, even though it was passed by the previous printf
call.
This is not guaranteed to happen, and obviously it's not the sort of thing you'd want to depend on, but it explains why you saw what you saw.
Good compilers help you avoid this kind of mistake by warning you when the number or type of your printf
arguments do not match the format string. For example, mine says
warning: format specifies type 'double' but the argument has type 'int'
If your compiler doesn't know how to print warnings like these, you might like to try to find a better one.
Upvotes: 2
Reputation: 1146
5 / 2
as an integer: 5 / 2 -> 2.ptinf()
is expecting a %f
.printf
loyally prints.To demonstrate this we can use a bigger number, 5000 / 3 for instance. You should properly cast your data, or use the proper literals 5.0 instead of 5.
#include <stdio.h>
int main(void)
{
printf("5/3 d:\t\t\t %d\n", 5/3);
// printf("5/3 n:\t\t\t %n\n", 5/3); // segfault
printf("5/3 f:\t\t\t %f\n", 5/3);
printf("(double) 5/3 d:\t\t %d \n", (double) 5/3);
// printf("(double) 5/3 n:\t\t %n \n", (double) 5/3); // memory corruption
printf("(double) 5/3 f:\t\t %f \n", (double) 5/3);
printf("(float) 5/3 d:\t\t %d \n", (float) 5/3);
// printf("(float) 5/3 n:\t\t %n \n", (float) 5/3); // memory corruption
printf("(float) 5/3 f:\t\t %f \n", (float) 5/3);
printf("5/3 d:\t\t\t %d \n", 5000/3);
// printf("5/3 n:\t\t\t %n \n", 5000/3); // segfault
printf("5/3 f:\t\t\t %f \n", 5000/3);
printf("5./3. d:\t\t %d \n", 5./3.);
// printf("5./3. n:\t\t %n \n", 5./3.); // memory corruption
printf("5./3. f:\t\t %f \n", 5./3.);
return 0;
}
output:
5/3 d: 1
5/3 f: 0.000000
(double) 5/3 d: 33989216
(double) 5/3 f: 1.666667
(float) 5/3 d: 33989216
(float) 5/3 f: 1.666667
5/3 d: 1666
5/3 f: 1.666667
5./3. d: 33989216
5./3. f: 1.666667
So, it doesn't matter if it's 5/2 or something else, what matters is the data type. In your case, the chain of casts: (float) (int) 5/2 = 1
accidentally happens to be equals to 30.0000 float.
Also, feeding 2 or 4 bytes integer into printf and telling it to expect 8 bytes (such as passing int and formatting as double), hopefully you'll get a segfault, if you're unlucky enough you'll get memory corruption and hard to track bugs.
Upvotes: 0
Reputation: 254
5 and 2 are integers, 5/2 is a integer too and truncated to the next int which is 2
try to cast (double)(5/2)
or use 5.0 / 2.0
Upvotes: 0
Reputation: 68023
you have the UB in that code. in the third printf - you pass integer but printf expects double - UB
cast it and it will work correctly https://godbolt.org/z/M3ysha
Upvotes: 3