Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ union element size based on other's element size

Tags:

c++

c++11

Consider the following piece of code:

struct S {     union     {         int arr1[10];         char arr2[sizeof(arr1)];     }; }; 

It compiles successfully with gcc 4.9.2 in c++03 and c++11 mode. However when I change S to be a template like so:

template <size_t N> struct S {     union     {            int arr1[N];         char arr2[sizeof(arr1)];     };   }; 

I get the following error output:

error: int S<10ul>::<anonymous union>::arr1 [10]’ is inaccessible

int arr1[N];

error: within this context

char arr2[sizeof(arr1)];

Clang compiles both versions only in c++11 mode. I am curious what is the correct behavior here. Maybe should I explicitly state that arr2 size is sizeof(int) * N?

like image 880
piotrekg2 Avatar asked Mar 02 '15 22:03

piotrekg2


People also ask

What determines the size of a union in C?

When we declare a union, memory allocated for a union variable of the type is equal to memory needed for the largest member of it, and all members share this same memory space. In above example, "char arr[8]" is the largest member. Therefore size of union test is 8 bytes.

Why is the size of a union greater than its members?

The alignment of your union must be the largest alignment of any of its members. This is 4. Therefore, the size of the union must be aligned to that size. It could have been 5 (as c is the largest member of the union), but because the alignment of the union as a whole is 4, the size of the union is padded to 8.

What is the size of the union?

However, the size of uJob is 32 bytes. It's because the size of a union variable will always be the size of its largest element. In the above example, the size of its largest element, ( name[32] ), is 32 bytes. With a union, all members share the same memory.


2 Answers

Your union is anonymous. Thus, the compiler will create arr1 and arr2 at class-level.
Because of this, char arr2[sizeof(arr1)]; won't refer to arr1 properly.

Here is a workaround :

template <size_t N> struct S {     union A     {            int arr1[N];         char arr2[sizeof(arr1)];     };   }; 

Compiles fine here : https://ideone.com/JcvOYg

By naming the union, we prevent the compiler from including it directly. It is then able to retrieve arr1 properly.

But it also means that arr1 and arr2 aren't not S's members anymore.

Finally, Members can be defined in terms of other members but the latter has to be "findable" by the compiler.

like image 109
Telokis Avatar answered Oct 23 '22 08:10

Telokis


You can do this:

template <size_t N> class S { private:     union     {         int arr1[N];         char arr2[N*sizeof(int)];     }; }; 
like image 26
amchacon Avatar answered Oct 23 '22 09:10

amchacon