Reputation: 5359
typedef struct { char ch; int num; } st_t;
typedef union { char *pch; st_t *pst; } un_t;
st_t st;
st.ch = 's';
un_t un = { &st.ch };
*un.pch = 'u';
printf("%c\n", un.pst->ch); // expect: print the letter 'u'
As far as I know, the address of the first member of the struct and the address of the struct itself are the same, so un
could both point to st
and st.ch
at the same time by accessing pst
and pch
. However, the C99 standard seems that it never explicitly says the sizes of different types of pointers are identical. Then, my concern is that will the code be corrupted such as violating strict aliasing rules, being undefined behavior, etc.?
Upvotes: 2
Views: 307
Reputation: 81189
The C Standard attempts to define characteristics, features, and guarantees which are required of all conforming implementations; it does not endeavor to describe most of the the useful characteristics and features that are common to 99% of implementations, but which are not required.
On the vast majority of implementations, all data pointers use the same representation, so given thingType *foo=xxx; void *vfoo = foo;
, both foo
and vfoo
will hold the same pattern of bits. Before the days of aggressive
optimizers, such implementations would quite usefully allow any kind of data
pointer to be accessed using a void**
, so one could write functions like:
int realloc_if_possible(void **p, int newsize)
{
void *temp = realloc(*p, newsize);
if (!temp) return -1;
*p = temp;
return 0;
}
but since the C Standard doesn't require compilers to recognize aliasing if the function is passed the address of any kind of pointer other than a void*, many modern compilers no longer support such constructs unless all type-based aliasing optimizations are disabled.
Upvotes: 0
Reputation: 224082
While a construct like this is not strictly conforming to the standard regarding pointer sizes, in practice the most common implementations (i.e. msvc, gcc/linux) do use the same representation for non-function pointers.
So on those implementation it should work as you would expect.
Upvotes: 0
Reputation: 25753
The line:
un_t un = {&st.ch};
*un.pch = 'u';
assigns the address of the member ch of the struct to the member pch of the union, and that pointer is then used to write a character to that address. This is completely correct.
There is a problem with the line that follows:
printf("%c\n", un.pst->ch);
The member of the union, other than the one that was last stored into, is read.
The following may be a trap1 representation2:
un.pst
1 (Quoted from: ISO/IEC 9899:201x 6.2.6.1 General 5 )
Certain object representations need not represent a value of the object type. If the stored
value of an object has such a representation and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a representation is produced
by a side effect that modifies all or any part of the object by an lvalue expression that
does not have character type, the behavior is undefined. 50) Such a representation is called
a trap representation.
2 (Quoted from: ISO/IEC 9899:201x 6.5.2.3 Structure and union members 3 footnote 95) )
If the member used to read the contents of a union object is not the same as the member last used to
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type
punning’’). This might be a trap representation.
Upvotes: 1