Unions in C Programming

A union in C is a special data type that allows storing different types of data in the same memory location. Unions are similar to structures in syntax and declaration but differ significantly in terms of memory management and usage.

A union is a user-defined data type, like a structure, but only one member of the union can hold a value at a time. This is because all members share the same memory location, unlike structures where each member has its own separate memory space. Unions are a powerful feature in C that offer memory efficiency and data representation flexibility. They are best suited for situations where only one variable in a group is used at any time. Understanding how memory is shared among union members is crucial to using them effectively and safely.

Why Use a Union?

  • To save memory when multiple variables are mutually exclusive (only one holds a value at a time).
  • To implement low-level programming constructs, such as interpreting the same memory differently (e.g., bit-level operations, hardware interfacing).
  • Useful in embedded systems and systems programming, where memory is limited and optimization is critical.

Syntax

Definition:

union union_name {
    data_type member1;
    data_type member2;
    ...
};
  • union_name: The name of the union type.
  • member1, member2, etc.: Variables (members) of possibly different types.

Declaration of Union Variables:

You can define and declare variables in two ways:

  • Separately:
union union_name variable_name;
  • Combined with definition:
union union_name {
    data_type member1;
    data_type member2;
} variable1, variable2;

Accessing Union Members

Union members are accessed using the dot operator (.), similar to structures.

Syntax:

union_variable.member_name;

Only one member holds a meaningful value at any given time. Writing to one member may overwrite data of another member.

Memory Behavior of Unions

  • A union allocates only one shared memory block, large enough to store the largest member.
  • This means that all members start at the same memory address.
  • Changing the value of one member affects all other members.
  • The size of the union is equal to the size of its largest member.
  • At any one time, only one member can hold a meaningful value.
  • All members of a union share the same memory location.

Memory Allocation Example:

For this union:

union Example {
    int i;       // 4 bytes
    float f;     // 4 bytes
    char str[20]; // 20 bytes
};

The total memory allocated for any variable of Example will be 20 bytes, which is the size of the largest member.

Union vs Structure – Key Differences

Feature Structure Union
Memory Allocation Separate memory for each member Shared memory for all members
Access All members can be used at once Only one member valid at a time
Size Sum of sizes of all members Size of largest member only
Use Case Hold multiple independent values Save memory when values are exclusive

Use Cases of Unions

  • Interpreting data in different formats (e.g., integers as byte arrays).
  • Embedded systems where performance and memory usage are critical.
  • Variant types or data structures that store different types of values under one variable.
  • Unions with structs for implementing efficient protocol parsers or hardware register representations.

Nested Unions and Arrays

You can nest unions within structures and vice versa. Arrays of unions can also be declared.

Union Inside a Structure:

struct Packet {
    int type;
    union {
        int intValue;
        float floatValue;
    } data;
};

In this case, based on the type, data can be accessed as an integer or float.

Pointers to Unions

Unions can be pointed to using pointers and accessed using the arrow operator (->), just like structures.

Pointer Syntax:

union union_name *ptr;
ptr->member_name;

This is useful for dynamic memory allocation or passing unions to functions.

Limitations of Unions

  • Only one member can be used at a time.
  • Unions do not support member initializations in their definitions (until C99 designated initializers).
  • Misuse can lead to confusing or undefined behavior if multiple members are read without proper management.