Search code examples
cgccunions

Can we do type conversions using unions?


Consider the following union:

union{
 uint32_t a;
 uint64_t b;
};

Both a and b reside in the same memory area. If we initialize the 32 bit integer a to some value, how is it possible to get b (when b was not initialized)? Does it mean that the compiler internally converts a to b

Thanks


Solution

  • The extra bytes in the uint64_t will have an unspecified value.

    From section 6.2.6.1 of the C standard:

    7 When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

    And section 6.5.2.3:

    3 A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member, 95) and is an lvalue if the first expression is an lvalue. If the first expression has qualified type, the result has the so-qualified version of the type of the designated member

    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.

    The only time this is allowed is if you have a union of one or more structs and each struct has an initial member of the same type.

    From section 6.5.2.3:

    6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

    Here's an example where this might be useful:

    union sockadddr_u {
        struct sockaddr sa;
        struct sockaddr_un sun;
        struct sockaddr_in sin;
    }
    

    These structures store information on sockets of different types. Most of the members differ, but the first member of each is of type sa_family_t whole value tells you the socket type. This allows you to inspect the first member of any of these members to figure out which of the members contains meaningful data its internal members.