Unions in C
Unions are like structures but all members share the same memory. Useful for saving memory when you only need one field at a time.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Understand how unions share memory
- ✓Know when to use union vs struct
- ✓Calculate union size (largest member)
- ✓Use unions for variant types
?Why Do We Need Unions?
Imagine you're building a system that handles different types of data, but at any given moment, you only need one type at a time. Why waste memory storing space for ALL types?
Without Unions
Using a struct wastes memory:
int i; // 4 bytes
float f; // 4 bytes
char s[20]; // 20 bytes
}; // Total: 28+ bytes
// Even if you only use one!
✓With Unions
Memory efficient:
int i; // 4 bytes
float f; // 4 bytes
char s[20]; // 20 bytes
}; // Total: 20 bytes only!
// Size of largest member
Save Memory
Store different types in same space
Variant Types
Handle data that can be any type
Type Punning
View same bytes as different types
01What is a Union?
A union is similar to a structure, but with one key difference: all members share the same memory location. This means a union can only hold one member's value at a time.
Structure vs Union Memory
Structure (Separate Memory)
Total: 12 bytes (with padding)
Union (Shared Memory)
int / float / char
All share same space
Total: 4 bytes (size of largest)
Key Difference
- • Structure: Each member has its OWN memory — can store all values
- • Union: All members SHARE memory — only ONE value at a time
02Declaring and Using Unions
1#include <stdio.h>23// Define a union4union Data {5 int i;6 float f;7 char c;8};910int main() {11 union Data data;12 13 // Store an integer14 data.i = 42;15 printf("data.i = %d\n", data.i);16 17 // Store a float (overwrites the integer!)18 data.f = 3.14;19 printf("data.f = %.2f\n", data.f);20 printf("data.i = %d (garbage now!)\n", data.i); // Corrupted!21 22 // Store a character (overwrites the float!)23 data.c = 'A';24 printf("data.c = %c\n", data.c);25 26 // Size of union = size of largest member27 printf("\nSize of union: %zu bytes\n", sizeof(data));28 printf("Size of int: %zu, float: %zu, char: %zu\n",29 sizeof(int), sizeof(float), sizeof(char));30 31 return 0;32}Output:
data.f = 3.14
data.i = 1078523331 (garbage now!)
data.c = A
Size of union: 4 bytes
Size of int: 4, float: 4, char: 1
How This Program Works
union Data data — Creates a union variable. Only 4 bytes allocated (size of largest member: int or float).
data.i = 42 — Stores 42 in those 4 bytes. Currently interpreted as an integer.
data.f = 3.14 — Overwrites the same 4 bytes with float representation of 3.14. Integer value is now garbage!
data.i now shows 1078523331 — the float's binary pattern interpreted as an integer (meaningless).
sizeof(data) returns 4 — always equals the largest member, not the sum of all members.
Important!
When you write to one union member, it overwrites ALL other members. Only the last written member contains valid data!
03Union Memory Layout
All union members start at the same memory address. The union's size equals the size of its largest member.
union Data { int i; float f; char c; }
All members start at address 0x1000 — they overlap completely!
1#include <stdio.h>23union Data {4 int i;5 float f;6 char c;7};89int main() {10 union Data data;11 12 // All members have the SAME address!13 printf("Address of data: %p\n", (void*)&data);14 printf("Address of data.i: %p\n", (void*)&data.i);15 printf("Address of data.f: %p\n", (void*)&data.f);16 printf("Address of data.c: %p\n", (void*)&data.c);17 18 // All print the same address!19 20 return 0;21}Union Size Rule
sizeof(union) = size of largest member (plus padding if needed)
04Structure vs Union Comparison
| Feature | Structure | Union |
|---|---|---|
| Keyword | struct | union |
| Memory | Each member has own space | All members share space |
| Size | Sum of all members (+padding) | Size of largest member |
| Access | All members at once | Only one member at a time |
| Use Case | Group related data | Store one of many types |
1#include <stdio.h>23struct StructExample {4 int i; // 4 bytes5 float f; // 4 bytes6 char c; // 1 byte (+3 padding)7}; // Total: 12 bytes89union UnionExample {10 int i; // 4 bytes11 float f; // 4 bytes12 char c; // 1 byte13}; // Total: 4 bytes (largest member)1415int main() {16 printf("Size of struct: %zu bytes\n", sizeof(struct StructExample));17 printf("Size of union: %zu bytes\n", sizeof(union UnionExample));18 19 return 0;20}05Practical Use Cases
1. Variant Type (Store Different Types)
1#include <stdio.h>2#include <string.h>34// A variant that can hold int, float, or string5typedef struct {6 int type; // 0 = int, 1 = float, 2 = string7 union {8 int i;9 float f;10 char str[20];11 } value;12} Variant;1314void printVariant(Variant v) {15 switch (v.type) {16 case 0: printf("Integer: %d\n", v.value.i); break;17 case 1: printf("Float: %.2f\n", v.value.f); break;18 case 2: printf("String: %s\n", v.value.str); break;19 }20}2122int main() {23 Variant v1 = {0, .value.i = 42};24 Variant v2 = {1, .value.f = 3.14};25 Variant v3;26 v3.type = 2;27 strcpy(v3.value.str, "Hello");28 29 printVariant(v1);30 printVariant(v2);31 printVariant(v3);32 33 return 0;34}2. Memory-Efficient Data Structures
1#include <stdio.h>23// Network packet that can be different types4typedef struct {5 int packetType; // 1 = text, 2 = binary, 3 = command6 int length;7 union {8 char text[256];9 unsigned char binary[256];10 struct {11 int commandId;12 int params[4];13 } command;14 } payload;15} Packet;1617int main() {18 Packet p;19 p.packetType = 1;20 p.length = 5;21 22 // Only 256 bytes for payload, not 256+256+20!23 printf("Packet size: %zu bytes\n", sizeof(Packet));24 25 return 0;26}3. Type Punning (Access Different Representations)
1#include <stdio.h>23// View the same bytes as different types4union FloatBits {5 float f;6 unsigned int bits;7 unsigned char bytes[4];8};910int main() {11 union FloatBits fb;12 fb.f = 3.14f;13 14 printf("Float value: %f\n", fb.f);15 printf("As integer (bits): 0x%08X\n", fb.bits);16 printf("As bytes: ");17 for (int i = 0; i < 4; i++) {18 printf("%02X ", fb.bytes[i]);19 }20 printf("\n");21 22 return 0;23}06Anonymous Unions (C11)
C11 introduced anonymous unions — unions without a name inside structures. This provides cleaner syntax when accessing union members.
Before C11 (Named Union)
struct Variant { int type; union { int i; float f; } value; // Union has a name};struct Variant v;v.value.i = 42; // Must use .valueC11+ (Anonymous Union)
struct Variant { int type; union { int i; float f; }; // No name! Anonymous};struct Variant v;v.i = 42; // Direct access!1#include <stdio.h>23// C11 feature: Anonymous unions in structs4typedef struct {5 enum { INT_TYPE, FLOAT_TYPE, STRING_TYPE } type;6 union { // Anonymous union - no name!7 int intVal;8 float floatVal;9 char strVal[32];10 }; // Note: no name here11} Value;1213int main() {14 Value v;15 16 // Direct access - no .value prefix needed!17 v.type = INT_TYPE;18 v.intVal = 42; // Cleaner syntax19 20 printf("Value: %d\n", v.intVal);21 22 v.type = FLOAT_TYPE;23 v.floatVal = 3.14f;24 printf("Value: %.2f\n", v.floatVal);25 26 return 0;27}28// Compile with: gcc -std=c11 anonymous_union.cC11 Benefit
Anonymous unions inside structs let you access union members directly like v.intVal instead of v.value.intVal. Use -std=c11 or later to enable this feature.
!Code Pitfalls: Common Mistakes & What to Watch For
These are the most common mistakes that trip up beginners. Study them carefully to avoid hours of debugging!
Reading Wrong Member
union Data d;d.f = 3.14;printf("%d", d.i); // WRONG! You stored a float, not int // This prints garbage/meaningless valueAlways read the same member you last wrote to!
Expecting All Values to Persist
union Data d;d.i = 42;d.f = 3.14;d.c = 'A';// WRONG assumption: all three values are stored// Only d.c is valid now - others are overwritten!Forgetting to Track Active Member
// BAD: No way to know which member is validunion Data { int i; float f; };// GOOD: Use a struct with type indicatorstruct TaggedUnion { int type; // Track which member is active union { int i; float f; } value;};09Frequently Asked Questions
Q:What's the difference between a union and a struct?
A: In a struct, each member has its own memory — size is the sum of all members (plus padding). In a union, all members share the same memory — size equals the largest member. Structs hold all fields simultaneously; unions hold one field at a time.
Q:When should I use unions?
A: Use unions for: (1) Variant types — a value that can be different types at different times, (2) Memory efficiency — when only one of several fields is needed, (3) Type punning — viewing the same bytes as different types (use carefully!), (4) Hardware/protocol formats.
Q:What happens if I read the wrong union member?
A: You get garbage or misinterpreted data. If you store an int and read it as a float, the same bits are interpreted differently. This is undefined behavior in strict C terms. Always track which member is active using a "tag" field (tagged/discriminated union pattern).
Q:What is a tagged union?
A: A union wrapped in a struct with an extra field indicating which member is valid. The "tag" (often an enum) tells you which union field to access. This is how you safely use unions — always check the tag before accessing the value.
Q:How big is a union?
A: A union's size equals the size of its largest member (plus any padding for alignment). If a union contains a char (1 byte) and an int (4 bytes), the union is 4 bytes. All members start at offset 0.
09Summary
What You Learned:
- ✓Union: All members share the same memory location
- ✓Size: Equals the size of the largest member
- ✓One at a time: Only one member holds valid data
- ✓Use cases: Variant types, memory efficiency, type punning
- ✓Best practice: Track which member is active with a type field
Test Your Knowledge
Related Tutorials
Structures in C
Group related data together! Create your own data types with struct. Store a student's name, age, and grade in one variable.
Recursion in C
Functions that call themselves! Learn this powerful technique, understand how it uses the stack, and know when to use it.
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!