0

This is my code. It Works fine with C but it is behaving like structures in C++.

#include<iostream>
using namespace std;
int main()
{
    union myunion
    {
        int B;
        double PI;
    };

    union myunion numbers;
    numbers.PI = 3.14;
    numbers.B = 12; 

    /* now storage of PI should be over-written */

    cout<<numbers.PI<<endl;
    cout<<numbers.B<<endl;

    /* Output is  3.14 */
    /*            12   */
    /* Why it is behaving like Structures ? */
    return 0;
}
Biffen
  • 6,249
  • 6
  • 28
  • 36
redb17
  • 143
  • 1
  • 14
  • 3
    If I'm not mistaken, this is undefined behavior in either C or C++. – Fred Larson Jan 11 '17 at 05:49
  • 1
    Reading a different member of a union from the last one written is UB in most cases. Possible duplicate http://stackoverflow.com/questions/2310483/purpose-of-unions-in-c-and-c/2313676#2313676 – doug Jan 11 '17 at 05:50
  • 2
    It appears I was mistaken about C. It's undefined in C++, though. See http://stackoverflow.com/q/25664848/10077. – Fred Larson Jan 11 '17 at 05:56

2 Answers2

6

Commenters have mentioned, and Cppreference on union states:

it's undefined behavior to read from the member of the union that wasn't most recently written.

Which is why your program is behaving as such: it's undefined behaviour. It could show the previous value, or crash, or anything in between.

numbers.PI = 3.14;
numbers.B = 12; 

cout<<numbers.PI<<endl; // undefined behaviour
Tas
  • 7,023
  • 3
  • 36
  • 51
  • So should one avoid using unions in C++ ? Because in C++ there behavior is UNDEFINED ? And also output is both the values as if DIFFERENT MEMORIES are used to store them ( but unions store it's members in a single memory locations ) – redb17 Jan 11 '17 at 06:42
  • 2
    @user7402737 You should not avoid using unions but you should not access the the member of union which was not most recently written. – Ajay Jan 11 '17 at 07:01
2

Others have explained to you why this is undefined behaviour - and why to never do this - but if you're still curious as to what's happening here: read on.

With the right compiler, on the right platform, during the right phase of the moon, the following happens.

  1. sizeof(double) == 8
  2. Setting numbers.PI to 3.14 sets 8 bytes in memory to 1f 85 eb 51 b8 1e 09 40 and displays numbers {B=1374389535 PI=3.1400000000000001} in the watch window
  3. sizeof(int) == 4
  4. So - when you set numbers.B to 12, only the first four bytes of that memory are changed. numbers is now stored as 0c 00 00 00 b8 1e 09 40 (the 0c000000 is 12 on my Intel processor) and the b81e09f0 are what was left behind of PI.
  5. As it happens, Intel, the IEEE and the compiler union packing order have led to the 12 trashing only the least significant bits of PI's mantissa (without disturbing its exponent).
  6. numbers is now shown in the watch window as numbers {B=12 PI=3.1399993896484428}

So, numbers.PI has been modified! It was 3.1400000000000001, and now it is 3.1399993896484428. But when you stream it to cout its new value gets rounded to 3.14 for display purposes, hiding the fact that its value has changed.

But remember - accessing any member of a union other than the one most recently set is still undefined behaviour.

Allison Lock
  • 2,375
  • 15
  • 17