Yet another printf question.

Started by
33 comments, last by Diodor 22 years, 5 months ago
I''m AP above.

Also, the size of int is dependent of the Operating system not the CPU.
Advertisement
I''ll try to explain better this time. I also changed the program a bit:

  #include <stdio.h>int main(int argc, char* argv[]){	float a = 0.5f;	printf ("%f %f\n", a, *(int*)&a);	return 0;}  



When calling printf, I pass it two params. One is a float value: a, the other one is the memory location of a, but as an int, not a float. a and *(int*)&a are the same memory location, and obviously, have the same 32 bits. (btw, I compiled in win32 console mode, so int is 4 bytes, as is float - I''ve double checked this).

Now from my understanding, the compiler should push both a and *(int*)&a on the stack, whether they are ints and floats. Then printf function would pop from the stack two floats with the var_arg macros (floats because of the "%f %f\n"). But because both 32 bits values pushed on the stack come from the same memory location and are identical, printf should print 0.50000 two times.

Still, I get 0.500000 0.00000.


If you still believe that there is any kind of rounding anywhere in the program:

  #include <stdio.h>int main(int argc, char* argv[]){	float a = 0.5f;	int* b = (int*)&a	int c = *b;	float d = *(float*)&c	printf ("%f\n", a);	printf ("%f\n", c);	printf ("%f\n", d);	return 0;}  


The result is :
0.5000000
0.0000000
0.5000000

instead of printf ("%f\n", c);

try

printf ("%d\n", c);



oh come on, how difficult is this to figure out? since you are explicitly casting your float type to an int, the decimal portion will be truncated, since your value is 0.5, it becomes 0. this is why c is a semi-type safe language. what you are doing doesn''t just put the same 32 bits on the stack, what you want to do is possible at the assembly language level, but c was designed so that there was *some* level of protection for the programmer.
Alright, can anyone explain why when I run the next program:

  int main(int argc, char* argv[]){	float a = 0.5f;	int* b = (int*)&a	int c = *b;	float d = *(float*)&c	printf ("%f\n", a);	printf ("%f\n", c);	printf ("%d\n", c);	printf ("%f\n", d);	return 0;}  


I get this output :

0.500000
0.000000
1056964608
0.500000

?

Everythink is OK except for the 0.000000 from the printf ("%f\n", c); line.
I was looking at the compiled asm, I understand what is happening.

Its pretty clear in the asm, but I'll explain anyway. printf needs to receive float's as double's, the 0.5f value is still being passed, it just not decoded because its not a double.

    /*00401029 C7 45 FC 00 00 00 3F mov         dword ptr [ebp-4],3F000000h3F000000h that's the hex value of 0.5fits being stored at [ebp-4]*/	float a = 0.5f;/*00401030 8D 45 FC             lea         eax,[ebp-4]address of your float00401033 89 45 F8             mov         dword ptr [ebp-8],eaxits being stored at [ebp-8]*/	int *b = (int*)&a/*00401036 8B 45 F8             mov         eax,dword ptr [ebp-8]loads address of float00401039 8B 08                mov         ecx,dword ptr [eax]loads float0040103B 89 4D F4             mov         dword ptr [ebp-0Ch],ecxits being stored at [ebp-0Ch]*/	int c = *b;/*0040103E 8B 45 F4             mov         eax,dword ptr [ebp-0Ch]loads your float00401041 89 45 F0             mov         dword ptr [ebp-10h],eaxits being stored at [ebp-10h]*/	float d = *(float*)&c/*00401044 D9 45 FC             fld         dword ptr [ebp-4]load your float00401047 83 EC 08             sub         esp,80040104A DD 1C 24             fstp        qword ptr [esp]stores it as double on stack0040104D 68 2C 61 42 00       push        offset string "%f" (0042612c)00401052 E8 79 00 00 00       call        printf (004010d0)00401057 83 C4 0C             add         esp,0Ch*/		printf ("%f\n", a);/*0040105A 8B 45 F4             mov         eax,dword ptr [ebp-0Ch]loads your float0040105D 50                   push        eaxputs it on the stack0040105E 68 2C 61 42 00       push        offset string "%f" (0042612c)00401063 E8 68 00 00 00       call        printf (004010d0)00401068 83 C4 08             add         esp,8*/	printf ("%f\n", c); //change this to printf ("%x\n", c); to see it in hex/*0040106B D9 45 F0             fld         dword ptr [ebp-10h]loads your float0040106E 83 EC 08             sub         esp,800401071 DD 1C 24             fstp        qword ptr [esp]stores it as double on stack00401074 68 1C 60 42 00       push        offset string "%d," (0042601c)00401079 E8 52 00 00 00       call        printf (004010d0)0040107E 83 C4 0C             add         esp,0Ch*/	printf ("%f\n", d);    


Edited by - burp on November 16, 2001 4:24:30 PM
Hello,

int* b = (int*)&a

It is assigning b an integer pointer with the address of a(float) which is converted to an int pointer. (Fine)

b is an int pointer to a floats value

Then

printf ("%f %f\n", a, *b);

displays a correctly


*b displays the value stored in a(but only the number of bytes that an int uses) as that int value converted to a float value

1056964608 == 0x3f000000 == 0.5f;
double(0.5f) == 0x3fe0000000000000 == 4602678819172646912





Edited by - burp on November 16, 2001 5:43:15 AM
Thanks burp, you are right. I still don''t understand how come passing a float as an argument can result in a double being pushed on the stack. Seems to me like a bug of VC.
quote:Original post by Diodor
Thanks burp, you are right. I still don''t understand how come passing a float as an argument can result in a double being pushed on the stack. Seems to me like a bug of VC.


No, you just don''t understand casting and C''s typing yet. Give it time.

This topic is closed to new replies.

Advertisement