We have two variables fa and fb of float type. We copy blocks of memory into variables of type void*.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
float fa = 2.11, fb = 2.2;
void *a, *b;
int *ffa, *ffb;
a = malloc(sizeof(float));
b = malloc(sizeof(float));
memcpy(a, &fa, sizeof(float));
memcpy(b, &fb, sizeof(float));
ffa = (int*)a;
ffb = (int*)b;
printf("ffa = %d\n", *ffa);
printf("ffb = %d\n", *ffb);
return 0;
}
After converting them to int type, we get huge numbers. Why is this happening?
ffa = 1074203197
ffb = 1074580685
CodePudding user response:
We copy blocks of memory into variables of type void*.
Careful. You are copying into memory pointed to by variables of type void *
. But, yes, you are copying blocks of memory. In particular, you are not assigning values, and therefore you have no possibility of converting values.
After converting them to int type, we get huge numbers.
Again, you have to be careful with your language. You did not convert anything to int
type. You converted two pointers from void *
type to int *
type. You converted the pointers. You did not convert the pointed-to values!
If you had said
float fa = 2.11;
int ia = (int)fa;
you would have converted the floating-point number 2.11 to the integer 2. But that's not what you did.
In IEEE-754 floating point, the number 2.11 is represented by the bit pattern 0x40070a3d
. (How it is that those crazy-looking bits actually represent the number 2.11 is a fascinating story, but beyond the scope of this answer.) And the hexadecimal number 0x40070a3d
in decimal is 1074203197, which is precisely the number you saw.
When you say
ffa = (int*)a;
you are not saying, "Hey compiler, those bits representing the floating-point number 2.11, I want you to convert them to an integer for me." (Again, to do that, you'd want int ia = (int)fa;
.) No, what this line says is "Hey, compiler, that pointer a
pointing to some bits representing a floating-point number, I want to pretend they're a pointer pointing to an integer."
In other words, you did not change the pointed-to bits. And, in a way, you didn't change the pointer, either: ffa
points to the exact same spot in memory that a
does. But what you very importantly changed was the interpretation of the pointed-to bits. a
is a pointer to a spot in memory where we expect there to be a value of type float
, while ffa
is a pointer to a spot in memory where we expect there to be a value of type int
.
So if you say
printf("%f\n", *a);
you have a pointer, a
, which is assumed to point to a float
, and you use *
to "take the contents of" the pointer, so you fetch the pointed-to value, and print it using %f
, and you see 2.11
.
But when you say
printf("ffa = %d\n", *ffa);
you have a pointer, ffa
, which is assumed to point to an int
, and you use *
to "take the contents of" the pointer, so you fetch the pointed-to value, and print it using %d
, and you see 1074203197
.
You have used pointers to take the same bit pattern, sitting in the same spot in memory, and interpret it in two different ways.
Interpreted as type float
, the bit pattern 0x40070a3d
is 2.11.
Interpreted as type int
, the bit pattern 0x40070a3d
is 1074203197.
This is a common (and powerful) use of pointers, although now that you're starting to understand it, I have to leave you with some cautions. Taking bit patterns in memory and reinterpreting them as different types, as we've been doing here, is actually a little more complicated than this question has made it look. In practice, there are two real-world complications that come into play, alignment and strict aliasing. At some point you may want to learn more about those.
CodePudding user response:
This is happening because floats are not integers and are saved differently in memory. Ints use methods like 2's or 1's complement while floats use methods like IEE.