1

I don't quite understand the output of the following code

union foo
{
    int a;
    double b;
};

int main()
{
    foo f;
    f.b = 12.0;
    cout << f.b << endl;

    f.a = 69;
    cout << f.b << endl;
    cout << f.a << endl;

    return 0;
}

Why does it print 12 12 69

The second 12 should have been garbage if I'm not mistaken. I'm using Visual Studio 2010.

chhenning
  • 2,017
  • 3
  • 26
  • 44

2 Answers2

6

Your code has a bug. The standard specifies that if you read from any union member other than the last one you wrote to, the results are unspecified. If you fix the code and comply with the standard, the mystery will go away.

Most likely, the compiler is optimizing the union away and just using two registers.

See section 6.2.6.1 or J.1 which states that "The value of a union member other than the last one stored into" is unspecified and may return any value that doesn't cause a trap.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • This sounds like a good answer. But what should I do when a function return a union and I don't know what the last used member is? Also, I'm using DEBUG code still the compiler is optimizing? – chhenning Apr 04 '13 at 22:03
  • 4
    You should throw your arms up in the air. I know you won't like to hear it, but that's all you can do. If the function is yours, fix it. If it is not yours, toss it. – R. Martinho Fernandes Apr 04 '13 at 22:04
  • @chhenning, There should be a member of the union that stores the last type. That's about the best you can hope for. – chris Apr 04 '13 at 22:04
  • 1
    @chris that would have to be a member of some other object. Unions without out-of-band information about the active member are unusable. (Guess why union types in C or C++ are not terribly useful; meanwhile, usable union types are the bread and butter of several other languages) – R. Martinho Fernandes Apr 04 '13 at 22:05
  • @R.MartinhoFernandes, Right, I prefer other solutions. You'd have to have an enclosing structure or something. It's a shame I use them anyway with things like [`INPUT`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx). – chris Apr 04 '13 at 22:07
  • We were talking about this in chat. It seems that C++11 retains the same wording as [this from C99 and C11](http://stackoverflow.com/a/11640381/922184). Wouldn't that run against the purely UB? Or did we misinterpret something? – Mysticial Apr 04 '13 at 22:14
  • On closer analysis. It seems that it's different between C11 and C++03/11. The answer I linked (which says that type-punning via union is allowed) only applies to C99 (TR2) and C11. In C++03 and C++11 type-punning via union remains UB but supported by practically every compiler. – Mysticial Apr 04 '13 at 22:25
5

If I print the value with more precision, I get

12.000000000000122569

for f.b after f.a = 69.

Undefined behaviour aside, what probably happens is that setting f.a only changes the least significant bits of the significand (sizeof(int) is probably 4, sizeof(double) 8), so you get a value that is close to the 12.0 you set initially, and the difference is too small for standard printing to show it.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431