-5

Below is some code that i wrote to understand typecasting but I do not understand why the value of float or double is being printed as "0.000000" even if i type cast from as array of integers or try to interpret from a union's address.

#include <stdio.h>

union test1
{
 int x;
 float y;
 double z;
};


int main()
{
 int x[2]={200,300};
 float *f;
 f=(float*)(x);
 printf("%f\n",*f); /*(1)why is this value 0.0*/

 *f=(float)(x[0]); /*(2)this works as expected and prints 200.00000*/
  printf("%f\n",*f);

  union test1 u;
  u.x=200;
  /*(3)this line give compilation error why*/
  //printf ("sizeof(test1) = %d \n", sizeof(test1));
  /*(4) this line also prints the value of float and double as 0.0000 why*/
  printf ("sizeof(test1) = %lu u.x:%d u.y:%f u.z:%lf \n", sizeof(u), u.x, u.y, u.z);
  return 0;

}

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Sandman
  • 13
  • Pick a language. Different languages work differently. – Kerrek SB Feb 25 '16 at 19:59
  • Title says "0.0000". Post says "0.000000". Suggest changing so they match to your true experience. – chux - Reinstate Monica Feb 25 '16 at 20:00
  • Casting doesn't change the data, it only changes the type the data will be interpreted as. Do a google search on how floating point data (for your architecture of choice) is stored and you will probably understand a little better. – mah Feb 25 '16 at 20:01
  • 1
    What you are doing is undefined behavior (UB). Using `"%e"` will help understand the UB better, but it is still UB. – chux - Reinstate Monica Feb 25 '16 at 20:02
  • 1
    @mah: Well... not really. Casting very well changes the representation of a value. For a pointer that would be the value of the pointer itself, but not of the data it points to - which is the problem here. C does not have the zoo of different cast operators like C++. – too honest for this site Feb 25 '16 at 20:08
  • Just a note that `*f=(float)(x[0]);` is also undefined, as `f` doesn't point to a float value. So it doesn't "work as expected" even if it prints 200.00000 – Bo Persson Feb 25 '16 at 20:19
  • i am not sure i understand you Bo why is *f=(float)(x[0]) any different than int y; f=3.5; y=(int)(f); or float f; int y; y=255; f=(float)(y); – Sandman Feb 25 '16 at 23:03

3 Answers3

5

First and foremost, int and float are not compatible types.

In your code, by saying

 f=(float*)(x);

you're breaking the strict aliasing rule. Any further usage invokes undefined behavior.

To put in simple words, you cannot just take a pointer to a float, cast that to an int * and dereference that int * to get an int value. To quote the wikipedia article,

[..] pointer arguments in a function are assumed to not alias if they point to fundamentally different types, [...]

For a much detailed description, please see the already linked FAQ answer.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • f=(float*)(&x); doesn't make a difference either right could you explain a little more – Sandman Feb 25 '16 at 20:02
  • Sorry for editing tags to remove C++ after you posted this answer! Culpa mea. Anyway, note that the Holy C++ Standard does not contain the term "strict aliasing". That's wholly a gcc notion, a particular compiler. Although it's strongly associated with a paragraph of the standard. – Cheers and hth. - Alf Feb 25 '16 at 20:02
  • @Cheersandhth.-Alf: It is "Mea Culpa". And the correct term would be "effective type", but the standard well mentions "aliasing". The "strict aliasing" you associate with gcc is another issue related to pointers. Note this is about C, not C++. – too honest for this site Feb 25 '16 at 20:05
  • 1
    @Olaf: Are you **sure** that the [word order](https://en.wikipedia.org/wiki/Latin_grammar) matters much in Latin? – Cheers and hth. - Alf Feb 25 '16 at 20:07
  • @Sandman added tadbit of explanation here, see the linked answer, that's a goldmine. :) – Sourav Ghosh Feb 25 '16 at 20:11
  • @Cheersandhth.-Alf: That's what I learned and I trust my old teacher more than Wikipedia. Also as a common phrase, there is some established order. But I will accept if that was some cultural difference. – too honest for this site Feb 25 '16 at 20:13
  • While the term is commonly used, @Cheersandhth.-Alf is right in that the standard does not. See 6.5p6 – too honest for this site Feb 25 '16 at 20:15
  • @Olaf Are you suggesting the wording to be `incompatible effective type`? Will that be better? – Sourav Ghosh Feb 25 '16 at 20:21
  • @SouravGhosh: I agree it is not that snappy as "strict aliasing". The choice is yours:-) – too honest for this site Feb 25 '16 at 20:30
  • @SouravGhosh Thanks i think i got it I see this undefined behavior because of the way float and int are stored and the same memory location/contents can't be just read off like that. – Sandman Feb 25 '16 at 23:05
3
printf("%f\n",*f); /*(1)why is this value 0.0*/

You are taking the address of an int and treating it like it contains a float. That is undefined behavior.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
0
printf("%f\n",*f); /*(1)why is this value 0.0*/

This is effectively undefined behavior, but saying this doesn't explain why you have 0.0 in your case. The result could have been anything because it is undefined behavior, but with a given compiler and a given machine, the behavior, while not specified, produced something.

You are reading as a float a memory that contains the encoding of an int; it is highly probable that the encoding of 200 as int, is read as a very small value (a denormalized small float number) as a float and written as 0.0. On my machine, denormalized float numbers are printed as 0.0 with printf (don't know if it is a standard printf behavior).

For float encoding, read IEEE 754.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69