Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an array of a union type be cast to a pointer of the active type?

Given an array of some union type, if the following conditions are met:

  • the active member of each union in the array is the same,
  • sizeof each member within the union is the same, and
  • alignof each member within the union is the same
  • (possibly) the union satisfies the requirements for StandardLayoutType

then are the following actions safe:

  1. casting this array to a pointer of the active type (for the intent of addressing it as an array of the active type)
  2. addressing anything other than the first element of the above array?
  3. assuming 1 & 2 are possible; does this hold for non standard-layout-types?

For example, consider the following code-segment:

template<typename T, typename U>
union storage_type
{
    T value0;
    U value1;
};

static_assert( sizeof(int) == sizeof(float), "" );
static_assert( alignof(int) == alignof(float), "" );

storage_type<int,float> storage[] = { {1}, {2}, {3} };

// the active type of all storage_type is 'int', so cast to int*
// to be treated as an array of ints

auto* array = reinterpret_cast<int*>(&storage[0]);

assert( array[0] == 1 );
assert( array[1] == 2 );
assert( array[2] == 3 );

I'm interested in what the C++ Standard has to explicitly say about such a case. I know that StandardLayoutTypes are safe to cast to the first member of the structure or active element of the union, so I suspect that my first cast is safe; but I'm unsure if this would hold true for an array, and treating it like an array of the active type.

I tried doing some searching, both on SO and in the C++ standard (N4660 C++17 draft) -- but I didn't have any luck

Note: This question is not about whether this will work in practice due to compilers having C compatibility; this is strictly a question on whether this invokes UB in C++, and whether it violates strict-aliasing rules.

like image 529
Human-Compiler Avatar asked Jan 30 '26 20:01

Human-Compiler


1 Answers

In theory, this can fail. As per standard:

The size of a union is sufficient to contain the largest of its data members.

So, in theory, sizeof(my_union) and sizeof(largest_member) might differ.

If you static_assert() that it's the same, then:

int* array = &storage[0].value0;

... does it and you're UB-free due to how array indexing works.

like image 140
lorro Avatar answered Feb 01 '26 10:02

lorro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!