15

I have a union in C like this:

union AUnion {
  struct CharBuf {
    char *buf;
    size_t len;
  } charbuf;
  uint8_t num;
  double fp_num;
};

My question is, can I guarantee that if given the following:

union AUnion u;

Then the following are true:

&u == &u.num
&u == &u.fp_num
&u == &u.charbuf

I.e they all start at the beginning of the memory segment where u is stored.

In the case of this C program compiled with gcc version 5.3.0 and -std=c11 the above is true:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

union AUnion {
    struct CharBuf {
        char *buf;
        size_t len;
    } charbuf;
    uint8_t num;
    double fp_num;
};

int main(void)
{
    union AUnion u;
    printf("%d\n", ((void*)&u) == ((void*)&u.charbuf));
    printf("%d\n", ((void*)&u.charbuf) == ((void*)&u.num));
    printf("%d\n", ((void*)&u.num) == ((void*)&u.fp_num));
}

As it prints:

1
1
1

Compiling the code above as C++11 with the same compiler results in the same output as compiling it as C11.

But is this standardized behaviour? Is it undefined? Can I rely on this behaviour with most C compilers? Can I expect this behaviour with C++ compilers as well?

jotik
  • 17,044
  • 13
  • 58
  • 123
A_User
  • 397
  • 1
  • 9
  • C++ doesn't treat union any differently than c – Uri Brecher Apr 24 '16 at 14:51
  • 1
    @UriBrecher actually there are many differences – M.M Apr 24 '16 at 15:11
  • 1
    @M.M: Then tell that how `union` differs in C & C++ ? List out the many differences If you think so !!! – Destructor Apr 24 '16 at 16:39
  • @Destructor too much to fit in comments. Post a question if you are curious (or find an existing one) – M.M Apr 24 '16 at 23:17
  • 1
    I guess you're right, there are some features that C++ adds to unions which are not supported in C. However, both languages exhibit the same behaviour in regards to aligning all members to the same position in memory. – Uri Brecher Apr 25 '16 at 04:18
  • Is there no good duplicate for this? I feel like this is a FAQ. – Lundin May 11 '16 at 12:55

2 Answers2

14

In 6.7.2.1p16 the C standard guarantees that:

The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.

So, yes, you can rely on all members starting at the unions address (note this is the same for the first member of a struct).

The C++ standard includes a similar sentence with respect to C-style (i.e. only C-style members) unions/structs, because C++ allows to pass unions to C functions which does require this layout.The relevant section in the C++ standard is 9.5.


However, note there might be padding bits inside standard simple types (integers, floats). And their internal may vary (endianess). You also might violate strict aliasing rule (C: effective type).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • This makes an assumption that pointer conversions can never change the memory address. This is untrue in C++. For example, multiple inheritance is one way to witness it. The fact that "suitably converted" has occurred does not prove _anything_ about where the members are in memory. – Asteroids With Wings Jul 31 '20 at 23:05
  • @AsteroidsWithWings Can you please cite the paragraph in the C++ standard? I'm not that familiar with C++ like I am with C, so I didn't expect ´union´s can be inherited at all. Plase note this is not about other types and only C-style members, which excludes inherited (wasn't I clear enough in my answer?). – too honest for this site Mar 06 '21 at 16:58
9

From my experience, I would say 'yes', though I've checked the C++14 standard and it even guarantees this. (c++11 will most likely have the same effects) Chapter 9.5 states: All non-static data members of a union object have the same address

So, you can depend on this behavior.

JVApen
  • 11,008
  • 5
  • 31
  • 67