6

C++11 allows an anonymous union to be defined in a function, and its members can be accessed as variables of the function. If I examine the pointers to the different members, they are the same, but the == operator says they're unequal.

Such strange behavior is typically the result of undefined behavior, but I don't see anything undefined in my code (I made sure to that both members are of the same type).

The behavior is different if I use a named variable of an unnamed union type. In this case, the pointers compare equal.

This program demonstrates both cases:

#include <iostream>
using namespace std;

#ifdef NAMED
// Create a named object of a union type
#define NAME n
#define ADDR(mem) &(NAME.mem)
#else
// Create an anonymous union in main()
#define NAME
#define ADDR(mem) &mem
#endif

int main()
{
    union {
        int a;
        int b;
    } NAME;

    cout << "&a = " << ADDR(a) << endl;
    cout << "&b = " << ADDR(b) << endl;
    cout << "(&a==&b) = " << (ADDR(a) == ADDR(b)) << endl;

    return 0;
}

When compiled with -DNAMED it prints to identical pointers, and 1 (equal pointers). Without -DNAMED, it again prints identical pointers, but then 0 (unequal pointers).

Tested with g++ 5.4.0, Ubuntu 16.04, x86_64.

ugoren
  • 16,023
  • 3
  • 35
  • 65
  • 1
    Seems that this behavior [changed since gcc 7](https://wandbox.org/permlink/H6kk2QrkHEqveebE). Might have been a compiler bug before. – ComicSansMS Apr 23 '18 at 09:32
  • Clang also reports `ADDR(a) == ADDR(b)` on trunk. – YSC Apr 23 '18 at 09:33
  • This is not UB per [class.union]/1 and [basic.life]/6. In function-scope, the name of non-static data members of anonymous unions are injected into the function scope. You're taking the address of objects after their allocation storage has been allocated and before their lifetime begun. As long as you treat those pointers as if there were `void*`, your program is well-defined. – YSC Apr 23 '18 at 09:38
  • see https://stackoverflow.com/a/49776289/5470596 for instance – YSC Apr 23 '18 at 09:38

1 Answers1

3

Your address checking is well defined (as YSC pointed out) and the standard guarantees that all members shall have the same address (cfr. [class.union]/3).

You must have stumbled upon a now fixed compiler bug.

Marco A.
  • 43,032
  • 26
  • 132
  • 246