Search code examples
cpointersundefined-behaviorunionsstrict-aliasing

Union of different types and sizes of pointers


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.?


Solution

  • 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.