The result is not defined.
I am just asking this from a theoretical point of view.
The complete chris's excellent answer:
What happens in your printf is undefined, but it could be quite similar to the code below (it depends on the actual implementation of the varargs, IIRC).
Disclaimer: The following is more "as-if-it-worked-that-way" explanation of what could happen in an undefined behaviour case on one platform than a true/valid description that always happens on all platforms.
Define "undefined" ?
Imagine the following code:
int main()
{
int i = 10 ;
void * pi = &i ;
double * pf = (double *) pi ; /* oranges are apples ! */
double f = *pf ;
/* what is the value inside f ? */
return 0;
}
Here, as your pointer to double (i.e. pf
) points to an address hosting an integer value (i.e. i
), what you'll get is undefined, and most probably garbage.
I want to see what's inside that memory !
If you really want to see what's possibly behind that garbage (when debugging on some platforms), try the following code where we will use an union to simulate a piece of memory where we will write either double or int data:
typedef union
{
char c[8] ; /* char is expected to be 1-byte wide */
double f ; /* double is expected to be 8-bytes wide */
int i ; /* int is expected to be 4-byte wide */
} MyUnion ;
The f
and i
field are used to set the value, and the c
field is used to look at (or modify) the memory, byte by byte.
void printMyUnion(MyUnion * p)
{
printf("[%i %i %i %i %i %i %i %i]\n"
, p->c[0], p->c[1], p->c[2], p->c[3], p->c[4], p->c[5], p->c[6], p->c[7]) ;
}
the function above will print the memory layout, byte by byte.
The function below will prinf the memory layout of different types of values:
int main()
{
/* this will zero all the fields in the union */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
printMyUnion(&myUnion) ; /* this should print only zeroes */
/* eg. [0 0 0 0 0 0 0 0] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.i = 10 ;
printMyUnion(&myUnion) ; /* the representation of the int 10 in the union */
/* eg. [10 0 0 0 0 0 0 0] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.f = 10 ;
printMyUnion(&myUnion) ; /* the representation of the double 10 in the union */
/* eg. [0 0 0 0 0 0 36 64] */
memset(myUnion.c, 0, 8 * sizeof(char)) ;
myUnion.f = 3.1415 ;
printMyUnion(&myUnion) ; /* the representation of the double 3.1415 in the union */
/* eg. [111 18 -125 -64 -54 33 9 64] */
return 0 ;
}
Note: This code was tested on Visual C++ 2010.
It doesn't mean it will work that way (or at all) on your platform, but usually, you should get results similar to what happens above.
In the end, the garbage is just the hexadecimal data set in the memory your looking at, but seen as some type.
As most types have different memory representation of the data, looking at the data in any other type than the original type is bound to have garbage (or not-so-garbage) results.
Your printf could well behave like that, and thus, try to interpret a raw piece of memory as a double when it was initially set as an int.
P.S.: Note that as the int and the double have different size in bytes, the garbage gets even more complicated, but it is mostly what I described above.
But I want to print an int as a double!
Seriously?
Helios proposed a solution.
int main()
{
int x=10;
printf("%f",(double)(x));
return 0;
}
Let's look at the pseudo code to see what's being fed to the printf:
/* printf("...", [[10 0 0 0]]) ; */
printf("%i",x);
/* printf("...", [[10 0 0 0 ?? ?? ?? ??]]) ; */
printf("%f",x);
/* printf("...", [[0 0 0 0 0 0 36 64]]) ; */
printf("%f",(double)(x));
The casts offers a different memory layout, effectively changing the integer "10" data into a double "10.0" data.
Thus, when using "%i", it will expect something like [[?? ?? ?? ??]], and for the first printf, receive [[10 0 0 0]] and interpret it correctly as an integer.
When using "%f", it will expect something like [[?? ?? ?? ?? ?? ?? ?? ??]], and receive on the second printf something like [[10 0 0 0]], missing 4 bytes. So the 4 last bytes will be random data (probably the bytes "after" the [[10 0 0 0]], that is, something like [[10 0 0 0 ?? ?? ?? ??]]
In the last printf, the cast changed the type, and thus the memory representation into [[0 0 0 0 0 0 36 64]] and the printf will interpret it correctly as a double.