0

In the following code I try to copy data from a float f to an int i, bit for bit, without any conversion of the data. I cast the address of f to (int*), and dereference this address when I assign it to i. The thinking is that if the program sees &f as an int pointer, it won't do a type conversion when (int*) f is dereferenced and assigned to i. But this isn't working and I do not understand why.

void main(){
  float f=3.0;
  int i;

  /* Check to make sure int and float have the same size on my machine */
  printf("sizeof(float)=%d\n",sizeof(float)); /* prints "sizeof(float)=4" */
  printf("sizeof(int)=%d\n",sizeof(int)); /* prints "sizeof(int)=4" */

  /* Verify that &f and (int*) &f have the same value */
  printf("&f = %p\n",&f); /* prints &f = 0x7ffc0670dff8 */
  printf("(int*) &f = %p\n",(int*) &f); /* prints (int*) &f = 0x7ffc0670dff8 */

  i=*((int*) &f);
  printf("%f\n", i); /* prints 0.000000 (I would have expected 3.000000) */
  return;
}
john smith
  • 619
  • 1
  • 9
  • 15

3 Answers3

1

By assigning via typecasting you are copying the raw 4 bytes of data from one variable to another. The problem is that a 3 in a 32-bit floating point variable isn't stored like a 3 in an integer variable.

For example, a 3 in 64-bit float format on a Mac is stored as 0x4e808000. Assigning that into an integer will produce 1077936128.

See https://en.wikipedia.org/wiki/IEEE_floating_point or http://www.madirish.net/240 or https://users.cs.duke.edu/~raw/cps104/TWFNotes/floating.html

EricS
  • 9,650
  • 2
  • 38
  • 34
1

Creating two pointers of unrelated types to the same object violates the strict aliasing rule. You want to avoid this, as in complicated code it can cause the compiler to produce binaries that don't do what you want. It's also undefined behaviour.

The correct way to change the type of a bit pattern in C between int and float is to avoid pointers completely, and use a union:

union int_float { int i; float f; };

int ival = (union int_float){ .f = 4.5 }.i;
float fval = (union int_float){ .i = 45 }.f;

Results may vary slightly. Be sure to check that the sizes of your floating type and your integer type are identical, or data will be lost/garbage data generated.

Note that it is possible to produce values in this way that are not valid elements of the destination type (this is more or less what you're seeing above when non-zero integer values get interpreted as floating-point zeroes despite not having all-zero bit patterns), which could lead to undefined or unexpected behaviour further down the line. Be sure to verify the output.

Community
  • 1
  • 1
Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
0

after the conversion you obtain an integer stored in the variable i. So if you wannt to print such a value you have to use:

printf("%d\n", i); /* prints 1077936128 */

Now the printf will interprets correctly the memory bits and print the correct value. This is not a cast but a bit copy like you said. Remember that ((int)&f) dereference that pointer into an int value. It won't do what you believe on machines where int and float have different sizes.

A different way to copy, if the sizes of int and float are identical, is:

memcpy(&i, &f, sizeof f);

After copying the four bytes contained in the memory area if we try to print the content as a sequence of four decimal values we can appreciate the redistribution just happened:

for floating:

3 160 0 3

for integer

0 204 204 0

This means that the four bytes are managed differently from the computer according to the type of rapresentation: int or float.

gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • If it's a bit copy, shouldn't the four decimal values be the same for both the float and the integer? – john smith Nov 21 '15 at 20:59
  • @johnsmith the four bytes cannot be the same because it's up to the computer rappresentation of int and float: this is the difference betweeen a int and a float on my computer. When you assign a value to a float and then copy it to an int area the computer will understand how correctly manage this – gaetanoM Nov 21 '15 at 21:05
  • 1
    There are many different ways a computer can store numbers - one's complement, two's complement, IEEE 754, BCD (binary coded decimal), SANE (old Mac 80-96 bit format), little endian, big endian, etc. Copying the raw bytes between the various formats does not work. The same number will have different bytes in each format. See https://en.wikipedia.org/wiki/Signed_number_representations – EricS Nov 21 '15 at 22:35
  • Yes you are right but my simple intention is to show the difference between a bit copy from a cast. I assume this is not enough clear to the person who posted the question. – gaetanoM Nov 21 '15 at 23:03