Assuming I have such a union
union buffer { struct { T* data; int count; int capacity; }; struct { void* data; int count; int capacity; } __type_erased; };
Am I having problems if I mix read / write anonymous structure members and __type_erased members according to the C11 alias rules?
In particular, I am interested in the behavior that occurs if they are accessed independently (for example, using different pointers). To illustrate:
grow_buffer(&buffer.__type_erased); buffer.data[buffer.count] = ...
I read all the relevant questions that I could find, but I still donβt understand it 100%, as some people seem to believe that this behavior is undefined, while others say that it is legal. In addition, the information I find is a combination of the rules C ++, C99, C11, etc., which are quite difficult to digest. Here I am clearly interested in the behavior set by C11 and presented by popular compilers (Clang, GCC)
Edit: additional information
Now I have done several experiments with several compilers and decided to share my conclusions if someone encounters a similar problem. The basis of my question is that I tried to write a convenient high-performance universal implementation of a dynamic array on simple C. The idea is that the array operation is performed using macros and heavy-duty operations (for example, to increase the array) is performed using a template template with an alias . For example, I might have a macro like this:
which increments the array, if necessary, and returns the index of the newly selected item. The specification (6.5.2.3) states that access to the same location through different union members is permitted. My interpretation of this is that although _array_ensure_size () does not know the type of union, the compiler should know that the __type_erased member could potentially be mutated by a side effect. That is, I would suggest that this should work. However, it seems that this is a gray area (and, frankly, the specification is really not clear on what constitutes access to membership). Apple's latest Clang (clang-800.0.33.1) has no problems with it. The code compiles without warning and works as expected. However, when compiling with GCC 5.3.0, the code crashes using segfault. In fact, I have a strong suspicion that the behavior of GCC is a mistake - I tried to make the mutation of the union member explicit by removing the mutable ref pointer and adopting a clear functional style, for example:
This works again with Clang, as expected, but calls GCC again. My conclusion is that extended type manipulations using connections are a gray area where you need to be carefully pushed through.