Prerequisite: Structures

Introduction

A union is similar to a struct, but its members share the same memory location. A union stores only can store and refer to only one of its field at a time. Not all fields can be accessed at the same time. This makes unions useful for memory-efficient representations of variables that are mutually exclusive. The size of a union is equal to the size of the largest member element inside of it.

Example

In the below example, a union represents a communication bus between a microcontroller and a peripheral device. The bus carries both the address and data information, but this happens at different cycles. Both data and address information cannot be sent at the same time as the total size of the bus is only 32 bits.

union comm_bus {
	uint32_t address;
	uint16_t data;
};

Definition

A union is defined using the union keyword.

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

This creates a type union value that can store an int, float, or char — but only one at a time. The size of the union is equal to the size of its largest member.

Declaration

Declaration of union refers to the use of our newly defined data type by allocating memory to it. Similar to structs, unions can also be automatically or dynamically allocated.

Note

Refer Declaration for all the methods of declaration of unions. There is no difference between declaration of a struct and union.

Initialization

Unions can be initialized positionally or with designated initializers (C99+).

1. Positional Initialization

union value v = {42};  // Initializes `i` with 42

This assigns 42 to the first member (i in this case).

2. Designated Initialization

union value v = {.f = 3.14};  // Initializes `f` with 3.14

Designated initializers are safer and more readable, especially when the union has many members.

Access

A union stores all its members in the same memory location, so only one member is valid at a time. Access depends on whether you have a union variable or a pointer to a union.

Accessing by Value (Stack Allocation)

When the union is declared as a normal variable, use the dot (.) operator to access members:

union value {
    int i;
    float f;
    char c;
};
 
union value v;
v.i = 42;        // Set integer member
printf("%d\n", v.i);  // Access integer member

Accessing by Pointer (Heap Allocation)

When you have a pointer to a union, use the arrow (->) operator to access members:

union value *v_ptr = malloc(sizeof(union value));
v_ptr->f = 3.14f;          // Set float member
printf("%f\n", v_ptr->f);  // Access float member
free(v_ptr);

Example Use Case

union data {
	uint32_t raw;
	struct {
		uint8_t lsb;
		uint8_t mid;
		uint8_t msb;
		uint8_t flags;
	};
};
 
union data packet;
packet.raw = 0xDEADBEEF;
printf("%X\n", packet.msb);  // Prints BE

This is commonly used in embedded systems for viewing and modifying specific bytes of a register or value.