Krishna Kanth Yenumula
Krishna Kanth Yenumula

Reputation: 2567

C union member gives particular/wrong value when other member is set to a new value. Why is this output in following code in C?

#include <stdio.h>
int main()
{
  union Data
  {
    char str[20];    
    int i;
    float f;
  }data;

  data.i=20;
  data.f=220.5;
  printf("%d\n",(data.i));

  return 0;
}

The output is:1130135552. I used gcc complier on Ubuntu 16.04 LTS.

Can someone explain the output?

The members data.i and data.f occupy same memory location, so output should be 220. But why output is 1130135552?

Upvotes: 3

Views: 763

Answers (5)

Rizwan
Rizwan

Reputation: 3666

As you are already aware that union shares memory location between the members inside. In case of union compiler allocated the memory equal to the max size of the member and use the same memory for all the members.

Hence when you execute data.f=220.5;, shared memory location between i and f holding data.i=20; got overwritten to a new value (220.5) with binary representation as follows :

enter image description here

Now again, when this value is read as a signed integer int it will be interpreted without conversion as 1130135552 in decimal representation. Hence you are getting 1130135552.

Further if you want to use all members of union, then struct is the answer.

struct Data
{
    char str[20];
    int i;
    float f;
} data;

data.i=20;
data.f=220.5;
printf("%d\n",data.i);

For more information on union and struct Please refer the following from Difference between Structure and Union: enter image description here

Upvotes: 6

Mike
Mike

Reputation: 4288

data.i and data.f share the same memory, but the interpretation of a value is different in integer and float.

With a float converter you get following values:

220.5 in float means: 
sign: 1
exponent: 134 
mantissa: 1.72265625 encoded as :6062080

binary representation:0 10000110 10111001000000000000000  (sign, exponent, mant.)
hex representation: 0x435c8000
dezimal representation:1130135552  (the value you get!!)

Upvotes: 1

joH1
joH1

Reputation: 567

As explicited by phoxis, the standard declares that the value is unspecified.

However, pragmatically, this is a good example of binary interpretation.

I assume the width for an int and float on your platform is 32 bits, and a floating-point value follows the IEEE 754 representation.

What happens here:

data.f=220.5;

This statement writes the floating-point value as binary 0100 0011 0101 1100 1000 0000 0000 0000 in the memory location of data, overwriting any previous value.

The next time the value is accessed is when read as an integer: data.i member access in your printf call. The value read, in binary, is still 0100 0011 0101 1100 1000 0000 0000 0000, and as a signed integer, this is interpreted without conversion as 1130135552.

If you want the value to be converted, you have to read the value as a floating-point (using data.f) and convert it to an integer value with a cast:

printf("%d\n",(int)(data.f));

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234715

If I may, let's restrict this answer to the case where sizeof(float) is the same as sizeof(int), that float is a single precision IEEE754 type, and int is a 2's complement type. If you don't understand what I'm saying here, ignore this paragraph for now: it's here in an attempt to make this answer watertight; a bit like the legalese in a financial contract.

A float is a remarkable type capable of representing numbers in a large range with a remarkable amount of precision. The format it uses internally to achieve this is a a complex one. If you want to know more, see https://en.wikipedia.org/wiki/IEEE_754.

When you write data.f = 220.5;, you are setting the first sizeof(float) bytes in your union to have the memory associated with the constant 220.5f.

But an int uses an entirely different format. When you output the int member of the union, you recover the int with value 1130135552. This is related to the 220.5f in that both have exactly the same pattern of bits.

The char str[20]; in your union is a red herring.

Upvotes: 2

phoxis
phoxis

Reputation: 61910

According to C11 Section 6.5.2.3 Footnote 95

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

The specific output depends on the layout of the members in memory and the type. Therefore, when you store data.f and then access data.i, the bit patterns in the memory of data.f is reinterpreted as an integer.

Note the following:

int a = 1;
float b = 1;

These two although may seem to have a similar layout on memory, but they are stored differently. In the case of integer, it will be generally stored in a two's complement format (although it can be other formats as well), and a floating point will be generally stored using the IEEE754 format (although it can be different). Therefore, trying to interpret a number stored using IEEE754 as integer will get you something totally different.

Also, not that, according to C11 Section 6.2.6.1 Paragraph 7

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

Therefore, if you assign to a member of an object of a union, then the values in the bytes of other location which is not used by the member which you assigned will have unspecified values.

Upvotes: 6

Related Questions