2

I have a strange behavior I'd like to understand. I have the following code:

    union floatInt
    { 
        float f;
        unsigned int l;
    };

    floatInt A, B;

    A.l = 0xFFA70B56;
    B.f = A.f;

    std::cout << std::hex << B.l << std::endl;

This works fine except in 1 configuration: Linux in non-debug mode, then I have this result: ffe70b56

And I don't really understand why the value has changed. I've been through several points to understand this:

  1. cppreference/union specifies that

    It's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union.

    But what would be the purpose of a union if we cannot use the other members? Moreover, it points to the same memory location, so it shouldn't be different.

  2. The value I'm using (0xFFA70B56) is NAN in IEEE 754 standard. So, when it is affected to another variable, can it be interpreted and changed to another NAN value like 0xFFE70B56?
  3. If I declare B as volatile, then the error disappears. Note that the variable isn't used anywhere else in the code. So has it something to do with compiler optimization?
timrau
  • 22,578
  • 4
  • 51
  • 64
Antho A
  • 78
  • 8
  • 3
    There's nothing _"working fine"_ with your code example. – πάντα ῥεῖ Oct 11 '16 at 14:34
  • wrap your union declaration with extern "C" which does preserve that behaviour - although why you'd want to try reusing the memory from a float & int I don't know. – UKMonkey Oct 11 '16 at 14:34
  • Thanks @πάνταῥεῖ, this helps me a lot! @UKMonkey, what would be different if I wrap my union declaration with extern C? I actually found several ways to avoid the wrong value now, like declaring B as volatile, or changing the way I affect B (`B.l = A.l` or `B = A`). But I would like to know what made this error happen. Is that related to one of the 3 points I enumerated, or several of them? Or is it something else? Thanks – Antho A Oct 11 '16 at 15:10
  • See http://stackoverflow.com/questions/2310483/purpose-of-unions-in-c-and-c for some clarification on why unions exist and what's allowed. – Mark Ransom Oct 11 '16 at 15:11
  • @AnthoA I just meant you should get the syntax right 1st at all. Hint: There's a missing semicolon after your union declaration. – πάντα ῥεῖ Oct 11 '16 at 15:15
  • @UKMonkey - wrapping the declaration with `extern "C"` won't affect the behavior. `extern "C"` doesn't mean "compile this as C code"; it means "use C name mangling and whatever else is needed to make this code linkable with C code". – Pete Becker Oct 11 '16 at 16:44

2 Answers2

1

But what would be the purpose of a union if we cannot use the other members?

The purpose of union is to save memory by using the same memory region for storing different objects at different times.

The memory occupied by your floatInt is the same of the memory occupied by a float variable. In case your goal is to use a union, I suggest to add a boolean element that keep track of which of the two elements is used.

If you want to use both attributes you should use struct or (we are in c++) class

For more about union read here

granmirupa
  • 2,780
  • 16
  • 27
0

Your NaN is being converted from a signalling NaN to a quiet NaN. The upper bit of the fraction, bit 22, changes from a zero to a one.

You might see the same behavior even if you weren't using a union.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Thanks! It clearly looks like my value has been converted to a qNaN, as only this bit 22 has been changed. Why don't I see it on other OS or in debug mode then? And why the volatile keyword prevent this conversion? Does this conversion depend on the compiler? So it is not a rule from C++ Standard – Antho A Oct 11 '16 at 15:52
  • @AnthoA the information on interactions between signalling NaN and quiet NaN is surprisingly hard to come by. I don't have a complete answer for you. The C++ standard doesn't mention NaN other than to provide a few functions to tell you if they're supported. – Mark Ransom Oct 11 '16 at 16:10