Memory Layout of Unions in C

Introduction to Unions in C

Unions in C are a specialized data structure that shares memory space among its members. Unlike structs, where each member occupies its own distinct memory location, unions allow multiple members to use the same memory address. This makes unions efficient for scenarios where memory efficiency is critical, such as storing data that changes dynamically.

Memory Layout Basics

When a union is declared, all members share the same memory space. The size of a union is determined by the largest member's size, not the sum of all members. For example, a union with a char (1 byte) and a int (4 bytes) will occupy 4 bytes. The order of members in the union is dictated by their declaration order, meaning the first member is stored first, followed by subsequent members.

Member Access and Overwriting

Each member of a union is accessed via a pointer, and the previous members are overwritten when a new member is assigned a value. For instance:

union {
    int a;
    float b;
    char c;
} u;

u.a = 10; // Overwrites b and c
u.b = 3.14; // Overwrites a and c
u.c = 'x'; // Overwrites a and b

This behavior ensures that the union's memory is dynamically managed based on the last accessed member.

Size Determination

The size of a union is calculated as the maximum size of any of its members. If a union contains members of varying sizes, the total size is the largest member's size. For example:

union {
    int i; // 4 bytes
    char c; // 1 byte
} u;

Here, the union is 4 bytes, even though the char member is smaller. This ensures that the union's memory is allocated efficiently.

Practical Examples

Consider a union used to store a student's grade:

union Student {
    int id;
    char name[20];
    float gpa;
} s;

s.id = 101;
s.name = "Alice";
s.gpa = 3.7;

When s.id is assigned, s.name and s.gpa are overwritten. This demonstrates how the union's memory is dynamically reused based on the last accessed member.

Conclusion

Unions in C are a powerful tool for optimizing memory usage, but their behavior requires careful management. Understanding how members are stored, overwritten, and sized is essential for writing correct and efficient code. By leveraging unions, developers can create compact data structures that adapt to changing data requirements.