Part 3 — Chapter 15

Chapter 15: Enum, Typedef and Union

C provides several additional language features that improve code readability, simplify data type usage, and optimize memory usage. Three commonly used features are enum, typedef, and union. These features are widely used in both general software development and low-level embedded systems programming.

1. Enum in C

An enum (enumeration) is a user-defined data type used to assign meaningful names to integer constants. Enums make programs significantly easier to read and maintain by replacing magic numeric constants with descriptive names.

Enum Syntax

Syntax
C
enum enum_name
{
    VALUE1,
    VALUE2,
    VALUE3
};
Example Program
led_states.c
C
#include <stdio.h>

enum LedState // Define enum type
{
    OFF,      // Assigned 0 by default
    ON        // Assigned 1 automatically
};

int main()
{
    enum LedState led = ON; // Declare and assign enum variable

    printf("LED State Value: %d\n", led); // Prints underlying integer value

    return 0;
}
Console Output
LED State Value: 1

How It Works

By default, the compiler assigns consecutive integer values to the enum members starting from 0. Here, OFF is assigned 0 and ON is assigned 1. Enums increase code readability significantly because descriptive names are much easier to understand than arbitrary numeric codes.

2. Typedef in C

The typedef keyword is used to establish a new alias name for an existing data type. It helps simplify complex declarations and guarantees portability across different hardware architectures.

Typedef Syntax

Syntax
C
typedef existing_type new_alias_name;
Example Program
type_aliases.c
C
#include <stdio.h>

typedef unsigned int uint; // Define "uint" as an alias for "unsigned int"

int main()
{
    uint value = 100; // Declare variable using the custom alias

    printf("Value: %u\n", value);

    return 0;
}
Console Output
Value: 100

How It Works

In this program, typedef creates the alias uint for unsigned int. The compiler treats uint exactly like the native unsigned int type, but using aliases keeps code clean, portable, and easy to maintain across different 8-bit, 16-bit, and 32-bit hardware architectures.

3. Union in C

A union is a custom data type where all member variables share the **exact same memory location**. Unlike structures (which allocate separate memory space for each member), a union's total allocated size is equal to the size of its largest member, meaning only one member can contain a valid value at any given instant.

Union Syntax

Syntax
C
union union_name
{
    data_type member1;
    data_type member2;
};
Example Program
shared_unions.c
C
#include <stdio.h>

union Data // Members share the exact same 4-byte block in memory
{
    int number;   // 4 Bytes
    float value;  // 4 Bytes
};

int main()
{
    union Data d;

    // 1. Assign and print integer data
    d.number = 10;
    printf("Integer: %d\n", d.number);

    // 2. Assign float data (Overwrites d.number)
    d.value = 5.5;
    printf("Float: %.1f\n", d.value);

    // 3. Printing d.number now reads floating-point bits as an integer (corrupt data)
    printf("Integer after overwrite: %d\n", d.number);

    return 0;
}
Console Output
Integer: 10
Float: 5.5
Integer after overwrite: 1085276160

Union Shared Memory Layout

Shared Memory Allocation & Overwrite Behavior of Union variable d
union Data d;
d.number = 10; // Stored as 0x0000000A in shared space
d.value = 5.5; // OVERWRITES exact same space with float representation (0x40B00000)
Base Address Union Member Shared Memory Representation Size in Memory
0x6000 d.number
[ 0x40B00000 ]
Contains Float 5.5. Integer data has been overwritten!
4 Bytes (int)
0x6000 d.value 4 Bytes (float)

How It Works

All members of a union share the exact same physical storage space. When you write d.value = 5.5, the floating-point IEEE-754 bit pattern overwrites the previous value of d.number. Attempting to print d.number afterwards displays 1085276160 (the raw integer translation of those float bits). Unions are incredibly powerful tools for memory optimization in resource-constrained environments.

Important Points

Keep these critical rules in mind when using enums, typedefs, and unions in C:

  • Enums: Enums define structured lists of readable integer constants. By default, values start at 0, but members can be assigned custom integer values explicitly.
  • Typedef: typedef is purely a compiler directive that creates aliases for existing data types, does not allocate any new memory.
  • Unions: Union members share the same memory location. The size of a union is equal to the size of its largest member, unlike a structure, which holds all elements contiguously.

Concept Overview

A quick summary of the visual relationships between these advanced data type features:

Enum → Assigns readable symbolic labels to integer constants
Typedef → Creates a clean alias name for an existing data type
Union → Stores multiple variables overlapping inside the same memory space

Embedded Focus

These features are heavily relied upon in embedded systems programming to construct highly optimized, ultra-clear firmware layers:

embedded_definitions.c
C
// 1. Typedefs abstract away hardware register widths
typedef unsigned char uint8_t;

// 2. Enums organize hardware state machines cleanly
enum DeviceState
{
    DEVICE_OFF,
    DEVICE_ON,
    DEVICE_ERROR
};

In firmware development, typedef abstracts variable widths across microcontrollers, enum eliminates mysterious magic numbers inside state machines, and union lets developers access 16-bit or 32-bit registers as raw bytes for SPI or UART packet transmissions without using manual memory pointers.

← Chapter 14: Structures Chapter 16: Storage Classes →