Unions in C

A union in C is a special data type that allows you to store different data types in the same memory location. Think of it like a shared storage box where you can put different types of items, but only one item at a time!

What Makes Unions Special?

Unlike structures where each member has its own memory space, all members of a union share the same memory location. This means:

  • Only one member can hold a value at any given time
  • The size of a union is equal to the size of its largest member
  • Unions help save memory when you need to store different types of data, but not simultaneously

Declaring a Union

The syntax for declaring a union is similar to structures, but uses the union keyword:

union DataType {
    int integer_val;
    float float_val;
    char char_val;
};

Creating Union Variables

You can create union variables in several ways:

// Method 1: Declare union first, then create variables
union DataType data1, data2;

// Method 2: Declare and create variables together
union DataType {
    int integer_val;
    float float_val;
    char char_val;
} data1, data2;

// Method 3: Using typedef
typedef union {
    int integer_val;
    float float_val;
    char char_val;
} DataType;

DataType data1, data2;

Accessing Union Members

Use the dot operator (.) to access union members:

#include <stdio.h>

union Number {
    int i;
    float f;
    char c;
};

int main() {
    union Number num;
    
    // Store an integer
    num.i = 42;
    printf("Integer: %d\n", num.i);
    
    // Store a float (overwrites the integer)
    num.f = 3.14;
    printf("Float: %.2f\n", num.f);
    
    // Store a character (overwrites the float)
    num.c = 'A';
    printf("Character: %c\n", num.c);
    
    return 0;
}

Memory Layout Example

Let's see how memory is shared in unions:

#include <stdio.h>

union Example {
    int i;      // 4 bytes
    float f;    // 4 bytes
    char c;     // 1 byte
};

int main() {
    union Example ex;
    
    printf("Size of union: %lu bytes\n", sizeof(ex));
    printf("Address of i: %p\n", &ex.i);
    printf("Address of f: %p\n", &ex.f);
    printf("Address of c: %p\n", &ex.c);
    
    return 0;
}

Output:

Size of union: 4 bytes
Address of i: 0x7fff5fbff6ac
Address of f: 0x7fff5fbff6ac
Address of c: 0x7fff5fbff6ac

Notice how all members have the same memory address!

Practical Use Cases

1. Type Conversion

union FloatBytes {
    float f;
    unsigned char bytes[4];
};

int main() {
    union FloatBytes fb;
    fb.f = 3.14159;
    
    printf("Float: %.5f\n", fb.f);
    printf("Bytes: ");
    for(int i = 0; i < 4; i++) {
        printf("%02X ", fb.bytes[i]);
    }
    printf("\n");
    
    return 0;
}

2. Variant Data Types

union Variant {
    int int_val;
    double double_val;
    char string_val[20];
};

struct Data {
    int type; // 1=int, 2=double, 3=string
    union Variant value;
};

Important Points to Remember

AspectUnionStructure
MemoryShared among all membersSeparate for each member
SizeSize of largest memberSum of all members
AccessOne member at a timeAll members simultaneously
Use CaseSave memory, variant typesGroup related data

Common Pitfalls

⚠️ Warning: Accessing a union member that wasn't the last one assigned can lead to unexpected results:

union Test {
    int i;
    float f;
};

int main() {
    union Test t;
    t.i = 42;
    printf("Float value: %.2f\n", t.f); // Undefined behavior!
    return 0;
}

Unions are powerful tools for memory optimization and low-level programming, but they require careful handling to avoid data corruption!