I thought I really understood this, and re-reading the standard (ISO 9899:1990) just confirms my obviously wrong understanding, so now I ask here.
The following prog
It's got to be defined behaviour. Think about it in terms of memory.
For simplicity, assume my_test is at address 0x80000000.
type1_p == 0x80000000
&type1_p->my_array[0] == 0x80000000 // my_array[0] == 1
&type1_p->my_array[1] == 0x80000004 // my_array[1] == 2
&type1_p->my_array[2] == 0x80000008 // my_array[2] == 3
When you cast it to type2_t,
type2_p == 0x80000000
&type2_p->ptr == 0x8000000 // type2_p->ptr == 1
type2_p->ptr[0] == *(type2_p->ptr) == *1
To do what you want, you would have to either create a secondary structure & assign the address of the array to ptr (e.g. type2_p->ptr = type1_p->my_array) or declare ptr as an array (or a variable length array, e.g. int ptr[]).
Alternatively, you could access the elements in an ugly manner : (&type2_p->ptr)[0], (&type2_p->ptr)[1]. However, be careful here since (&type2_p->ptr)[0] will actually be an int*, not an int. On 64-bit platforms, for instance, (&type2_p->ptr)[0] will actually be 0x100000002 (4294967298).