Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union not reinterpreting values?

Consider this program:

#include <stdio.h>

union myUnion
{
    int x;
    long double y;
};

int main()
{
    union myUnion a;
    a.x = 5;
    a.y = 3.2;
    printf("%d\n%.2Lf", a.x, a.y);
    return 0;
}

Output:

-858993459
3.20

This is fine, as the int member gets interpreted using some of the bits of the long double member. However, the reverse doesn't really apply:

#include <stdio.h>

union myUnion
{
    int x;
    long double y;
};

int main()
{
    union myUnion a;
    a.y = 3.2;
    a.x = 5;
    printf("%d\n%.2Lf", a.x, a.y);
    return 0;
}

Output:

5
3.20

The question is why the long double doesn't get reinterpreted as some garbage value (since 4 of its bytes should represent the integer)? It is not a coincidence, the program outputs 3.20 for all values of a.x, not just 5.

like image 474
DarkAtom Avatar asked Sep 20 '19 17:09

DarkAtom


Video Answer


1 Answers

However, the reverse doesn't really apply

On a little endian system (least significant byte of a multi-byte value is at the lowest address), the int will correspond to the least significant bits of the mantissa of the long double. You have to print that long double with a great deal of precision to see the effect of that int on those insignificant digits.

On a big endian system, like a Power PC box, things would be different: the int part would line up with the most significant part of the long double, overlapping with the sign bit, exponent and most significant mantissa bits. Thus changes in x would have drastic effects on the observed floating-point value, even if only a few significant digits are printed. However, for small values of x, the value appears to be zero.

On a PPC64 system, the following version of the program:

int main(void)
{
    union myUnion a;
    a.y = 3.2;
    int i;
    for (i = 0; i < 1000; i++) {
      a.x = i;
      printf("%d -- %.2Lf\n", a.x, a.y);
    }
    return 0;
}

prints nothing but

1 -- 0.0
2 -- 0.0
[...]
999 - 0.0

This is because we're creating an exponent field with all zeros, giving rise to values close to zero. However, the initial value 3.2 is completely clobbered; it doesn't just have its least significant bits ruffled.

like image 120
Kaz Avatar answered Oct 04 '22 22:10

Kaz