Lecture 17

Unions and Enumerations in C

Unit IV: Structures and Pointers

Topics Covered

Unions in C - Declaration, Size, Nested & Anonymous
Applications of Unions
Structure vs Union Comparison
Enumerations (enum) in C
Enum Variables, Initialization & Applications

Dr. Mohsin Dar

Assistant Professor, Cloud & Software Operations Cluster (SOCS)

University of Petroleum and Energy Studies (UPES)

Introduction to Unions

What is a Union?

A union is a user-defined data type that allows storing different data types in the same memory location
All members share the same memory space
Only ONE member can hold a value at any given time
Useful for memory-efficient storage when only one member is used at a time
Key Point: Unlike structures where each member has its own memory, unions allocate memory equal to the largest member size, and all members share this space.
// Basic Union Syntax union Data { int i; float f; char str[20]; };

Union Declaration

Declaration and Initialization

// Method 1: Declare union type first union Employee { int id; float salary; char name[50]; }; union Employee emp1, emp2; // Method 2: Declare with union definition union Student { int roll_no; float marks; char grade; } s1, s2, s3; // Method 3: Using typedef typedef union { int x; float y; } Point; Point p1, p2;
Union members are accessed using dot (.) operator
Pointer to union uses arrow (->) operator

Size of Union

Memory Allocation in Unions

Union Data

int i (4 bytes)
float f (4 bytes)
char str[20] (20 bytes)

Total Size: 20 bytes

Important: Size of union = Size of largest member (considering alignment)
#include <stdio.h> union Data { int i; // 4 bytes float f; // 4 bytes char str[20]; // 20 bytes }; int main() { union Data data; printf("Size of union: %lu bytes\n", sizeof(data)); // Output: Size of union: 20 bytes return 0; }

Working with Unions - Example

#include <stdio.h> #include <string.h> union Data { int i; float f; char str[20]; }; int main() { union Data data; data.i = 10; printf("data.i: %d\n", data.i); // Output: 10 data.f = 220.5; printf("data.f: %.1f\n", data.f); // Output: 220.5 printf("data.i: %d\n", data.i); // Garbage value! strcpy(data.str, "C Programming"); printf("data.str: %s\n", data.str); // Output: C Programming printf("data.f: %.1f\n", data.f); // Garbage value! return 0; }
Warning: When you assign a value to one member, other members' values become unreliable (garbage). Only the last assigned member holds valid data.

Nested Unions

Union Inside Structure or Another Union

// Union inside Structure struct Employee { char name[50]; int id; union { float salary; int hourly_rate; } pay; }; int main() { struct Employee emp; strcpy(emp.name, "John Doe"); emp.id = 101; emp.pay.salary = 50000.50; printf("Name: %s\n", emp.name); printf("ID: %d\n", emp.id); printf("Salary: %.2f\n", emp.pay.salary); return 0; }
Nested unions allow flexible data representation within structures
Useful when different members require different data types

Anonymous Unions

Unions Without Names (C11 Standard)

struct Product { char name[30]; int id; // Anonymous union - no name needed union { float price; int discount_percent; }; // No variable name! }; int main() { struct Product p; strcpy(p.name, "Laptop"); p.id = 501; p.price = 45000.00; // Direct access, no intermediate name printf("Product: %s\n", p.name); printf("Price: %.2f\n", p.price); return 0; }
Advantage: Anonymous unions provide cleaner syntax - members can be accessed directly without intermediate union variable name.

Applications of Unions in C

Practical Use Cases

Memory Optimization: Save memory when only one member is needed at a time
Type Punning: View same data in different formats (inspect bytes of float/int)
Variant Data Types: Store different types of data based on context
Hardware Register Access: Access hardware registers in multiple ways
Protocol Implementation: Handle different message types in network programming
// Example: IP Address representation union IPAddress { unsigned int full_address; // 32-bit representation struct { unsigned char octet1; unsigned char octet2; unsigned char octet3; unsigned char octet4; } octets; // Individual byte access }; int main() { union IPAddress ip; ip.octets.octet1 = 192; ip.octets.octet2 = 168; ip.octets.octet3 = 1; ip.octets.octet4 = 1; printf("IP: %d.%d.%d.%d\n", ip.octets.octet1, ip.octets.octet2, ip.octets.octet3, ip.octets.octet4); return 0; }

Difference Between Structure and Union

Aspect Structure Union
Keyword struct union
Memory Allocation Each member gets separate memory All members share same memory
Size Sum of all members' sizes (+ padding) Size of largest member
Value Storage All members can hold values simultaneously Only ONE member holds value at a time
Access All members accessible anytime Only last assigned member is valid
Use Case Related data that exists together Alternative data representations

Structure

Member A: 4 bytes

Member B: 4 bytes

Member C: 8 bytes

Total: 16 bytes

Union

Member A: 4 bytes

Member B: 4 bytes

Member C: 8 bytes

Total: 8 bytes

Enumeration (enum) in C

What is an Enumeration?

User-defined data type consisting of named integer constants
Makes code more readable and maintainable
By default, first value is 0, then increments by 1
Provides meaningful names instead of magic numbers
// Basic enum syntax enum WeekDay { SUNDAY, // 0 MONDAY, // 1 TUESDAY, // 2 WEDNESDAY, // 3 THURSDAY, // 4 FRIDAY, // 5 SATURDAY // 6 }; enum WeekDay today = MONDAY;
Advantage: Using MONDAY instead of 1 makes code self-documenting and easier to understand!

Creating Enum Variables

Different Ways to Declare Enum Variables

// Method 1: Define enum then declare variables enum Color { RED, GREEN, BLUE }; enum Color favorite_color; enum Color background_color; // Method 2: Declare variables with enum definition enum Status { SUCCESS, FAILURE, PENDING } task_status, operation_status; // Method 3: Using typedef for cleaner syntax typedef enum { NORTH, SOUTH, EAST, WEST } Direction; Direction current_direction = NORTH; // No need for 'enum' keyword
Method 1: Separate definition and declaration
Method 2: Combined definition with variable declaration
Method 3: Using typedef for shorter, cleaner syntax

Enum Initialization

Custom Values for Enum Constants

// Default values (starts from 0) enum Default { A, // 0 B, // 1 C // 2 }; // Custom starting value enum Month { JAN = 1, // 1 FEB, // 2 MAR, // 3 APR // 4 }; // Assigning specific values enum ErrorCode { FILE_NOT_FOUND = 404, SERVER_ERROR = 500, UNAUTHORIZED = 401, SUCCESS = 200 }; // Mixed initialization enum Priority { LOW = 1, MEDIUM, // 2 (increments from previous) HIGH = 10, CRITICAL // 11 (increments from previous) };
Note: After a manually assigned value, subsequent values increment by 1 automatically.

Assigning Values Manually - Example

#include <stdio.h> enum WeekDay { SUNDAY = 1, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }; int main() { enum WeekDay today; today = WEDNESDAY; if (today == SATURDAY || today == SUNDAY) { printf("It's weekend! Day number: %d\n", today); } else { printf("It's a weekday. Day number: %d\n", today); } // Using enum in switch statement switch(today) { case MONDAY: printf("Start of work week!\n"); break; case FRIDAY: printf("Last working day!\n"); break; case SATURDAY: case SUNDAY: printf("Weekend!\n"); break; default: printf("Midweek day\n"); } return 0; }

Size of Enums

Memory Allocation for Enumerations

#include <stdio.h> enum Boolean { FALSE, TRUE }; enum Color { RED, GREEN, BLUE, YELLOW }; int main() { printf("Size of enum Boolean: %lu bytes\n", sizeof(enum Boolean)); printf("Size of enum Color: %lu bytes\n", sizeof(enum Color)); printf("Size of int: %lu bytes\n", sizeof(int)); // Output (typically): // Size of enum Boolean: 4 bytes // Size of enum Color: 4 bytes // Size of int: 4 bytes return 0; }
Important: Enums are typically stored as integers (4 bytes on most systems), regardless of the number of constants defined.
Enum size is compiler-dependent but usually same as int
All enum values are integer constants
Size doesn't depend on number of enum constants

Enum and Typedef

Simplifying Enum Usage with Typedef

// Without typedef - verbose enum TrafficLight { RED_LIGHT, YELLOW_LIGHT, GREEN_LIGHT }; enum TrafficLight signal1; // Need to use 'enum' keyword enum TrafficLight signal2; // With typedef - cleaner syntax typedef enum { SMALL, MEDIUM, LARGE, EXTRA_LARGE } Size; Size shirt_size = MEDIUM; // No 'enum' keyword needed! Size pizza_size = LARGE; // Another typedef example typedef enum { ADMIN = 1, USER = 2, GUEST = 3 } UserRole; UserRole current_user = ADMIN;
Typedef eliminates need to write 'enum' keyword repeatedly
Makes code cleaner and more readable
Common practice in professional C programming

Applications of Enums in C

Real-World Use Cases

State Machines: Representing different states in a system
Menu Options: Defining menu choices in applications
Error Codes: Meaningful error handling
Configuration Flags: System settings and modes
Direction/Position: Game development, navigation
// Example 1: Traffic Control System typedef enum { RED, YELLOW, GREEN } TrafficSignal; void controlTraffic(TrafficSignal signal) { switch(signal) { case RED: printf("STOP!\n"); break; case YELLOW: printf("READY...\n"); break; case GREEN: printf("GO!\n"); break; } } // Example 2: File Operations typedef enum { FILE_SUCCESS = 0, FILE_NOT_FOUND = -1, FILE_ACCESS_DENIED = -2, FILE_CORRUPT = -3 } FileStatus;

Complete Enum Application Example

#include <stdio.h> typedef enum { CHECKING = 1, SAVINGS, FIXED_DEPOSIT } AccountType; typedef enum { ACTIVE, INACTIVE, SUSPENDED } AccountStatus; struct BankAccount { int account_number; AccountType type; AccountStatus status; float balance; }; void displayAccount(struct BankAccount acc) { printf("\n--- Account Details ---\n"); printf("Account Number: %d\n", acc.account_number); printf("Type: "); switch(acc.type) { case CHECKING: printf("Checking\n"); break; case SAVINGS: printf("Savings\n"); break; case FIXED_DEPOSIT: printf("Fixed Deposit\n"); break; } printf("Status: "); switch(acc.status) { case ACTIVE: printf("Active\n"); break; case INACTIVE: printf("Inactive\n"); break; case SUSPENDED: printf("Suspended\n"); break; } printf("Balance: $%.2f\n", acc.balance); } int main() { struct BankAccount acc1 = {12345, SAVINGS, ACTIVE, 5000.50}; displayAccount(acc1); return 0; }

Union, Structure, and Enumeration Comparison

Feature Structure Union Enumeration
Purpose Group related data Store alternative data Named integer constants
Memory Separate for each member Shared by all members Size of int
Access All members simultaneously One member at a time Named constants only
Size Sum of all members Largest member Typically 4 bytes
Use Case Employee records, coordinates Type conversion, variant data Days, states, error codes
Data Types Multiple types Multiple types Integer only

Bit-Fields in C

Compact Storage Using Bits

Allows packing several values into limited bits within a structure
Useful for memory-constrained embedded systems
Syntax: datatype member_name : bit_width;
struct PackedData { unsigned int a : 2; // 2 bits (0-3) unsigned int b : 3; // 3 bits (0-7) unsigned int c : 3; // 3 bits (0-7) }; // Total: 8 bits = 1 byte (instead of 12 bytes!) // Example: Hardware Register struct StatusRegister { unsigned int ready : 1; // 1 bit flag unsigned int error : 1; // 1 bit flag unsigned int busy : 1; // 1 bit flag unsigned int mode : 2; // 2 bits (0-3) unsigned int reserved : 3; // 3 bits unused }; int main() { struct StatusRegister reg; reg.ready = 1; reg.error = 0; reg.busy = 1; reg.mode = 2; printf("Size: %lu byte(s)\n", sizeof(reg)); printf("Ready: %u, Error: %u, Busy: %u, Mode: %u\n", reg.ready, reg.error, reg.busy, reg.mode); return 0; }
Memory Savings: Bit-fields can dramatically reduce memory usage in structures with many small-range values!

Summary - Key Takeaways

Unions

Share memory among members - only one active at a time
Size = largest member size
Used for memory optimization and type conversion
Support nested and anonymous unions

Enumerations

Named integer constants for better code readability
Default values start at 0 and increment
Can assign custom values manually
Typedef makes enum usage cleaner

Bit-Fields

Pack multiple values in limited bits
Excellent for memory-constrained systems
Common in hardware programming
Remember: Choose structures for related data, unions for alternative representations, and enums for named constants. Each serves a specific purpose in efficient C programming!

Thank You!

Questions?

Dr. Mohsin Dar

Assistant Professor

Cloud & Software Operations Cluster (SOCS)

University of Petroleum and Energy Studies (UPES)

Next Lecture

Advanced Pointer Concepts and Dynamic Memory Allocation

Keep practicing! Master these concepts through hands-on coding.

1 / 21