0

Here's the code:

#include <stdio.h>

union
{
    unsigned u;
    double d;
} a,b;

int main(void)
{
    printf("Enter a, b:");
    scanf("%lf %lf",&a.d,&b.d);
    if(a.d>b.d)
    {
        a.u^=b.u^=a.u^=b.u;
    }
    printf("a=%g, b=%g\n",a.d,b.d);
    return 0;
}

The a.u^=b.u^=a.u^=b.u; statement should have swapped a and b if a>b, but it seems that whatever I enter, the output will always be exactly my input.

nalzok
  • 14,965
  • 21
  • 72
  • 139
  • 3
    I just have to say that if readability and maintainability are of any value to you you should find a simpler way to accomplish this task. Not an answer I know but... – JJF Nov 26 '15 at 01:07
  • 4
    Think about how unions work, and consider sizeof(a.u) vs sizeof(a.d). – keithmo Nov 26 '15 at 01:11
  • 2
    I think (but I'm not sure) that writing to `a.d` then reading from `a.u` is undefined behaviour. Do you have optimizations on? – user253751 Nov 26 '15 at 01:14
  • @keithmo I get you, thanks! – nalzok Nov 26 '15 at 01:15
  • @immibis I'm not sure. As a newbie programmer, I just open code::blocks, type my code, then press F9. I didn't touch anything about the compiler. – nalzok Nov 26 '15 at 01:17
  • Could you explain what the purpose of this code is? – M.M Nov 26 '15 at 01:43
  • @immibis union aliasing is not UB unless a trap representation is formed, [see here](http://stackoverflow.com/questions/11639947/is-type-punning-through-a-union-unspecified-in-c99-and-has-it-become-specified) – M.M Nov 26 '15 at 01:44
  • @M.M To swap two double floats, a and b, when necessary, to ensure that a<=b without using a third variable. – nalzok Nov 26 '15 at 02:20

3 Answers3

2

a.u^=b.u^=a.u^=b.u; causes undefined behaviour by writing to a.u twice without a sequence point. See here for discussion of this code.

You could write:

unsigned tmp;
tmp = a.u;
a.u = b.u;
b.u = tmp;

which will swap a.u and b.u. However this may not achieve the goal of swapping the two doubles, if double is a larger type than unsigned on your system (a common scenario).

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
1

It's likely that double is 64 bits, while unsigned is only 32 bits. When you swap the unsigned members of the unions, you're only getting half of the doubles.

If you change d to float, or change u to unsigned long long, it will probably work, since they're likely to be the same size.

You're also causing UB by writing to the variables twice without a sequence point. The proper way to write the XOR swap is with multiple statements.

b.u ^= a.u;
a.u ^= b.u;
b.u ^= a.u;

For more about why not to use XOR for swapping, see Why don't people use xor swaps?

Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

In usual environment, memory size of datatype 'unsigned' and 'double' are different. That is why variables are not look like changed.

And you cannot using XOR swap on floating point variable. because they are represented totally different in memory.