Part 4 — Chapter 16

Chapter 16: Storage Classes

In C, every variable has a scope, lifetime, and storage location associated with it. Storage classes define how variables are stored in memory, where they can be accessed (scope), and how long they remain available (lifetime) during program execution.

C provides four main storage classes: auto, register, static, and extern.

1. auto Storage Class

The auto storage class is the default for local variables declared inside any function block. These variables are allocated automatically inside the Stack frame when the function is called, and are destroyed when execution exits the block.

Example Program
auto_vars.c
C
#include <stdio.h>

int main()
{
    auto int value = 10; // Declared using auto (default)

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

    return 0;
}
Console Output
Value: 10

How It Works

Since auto is the default storage class for local variables, writing the keyword auto explicitly is completely optional and redundant. The variable exists on the system Stack and can only be accessed inside the function block where it is defined.

2. register Storage Class

The register storage class asks the compiler to store a variable directly in a physical **CPU Register** instead of RAM, allowing for ultra-fast arithmetic and pointer access. This is commonly recommended for extremely high-frequency variables like loop indices.

Example Program
loop_counters.c
C
#include <stdio.h>

int main()
{
    register int i; // Suggests placing 'i' in a CPU register

    for (i = 0; i < 5; i++)
    {
        printf("i: %d\n", i);
    }

    return 0;
}
Console Output
i: 0
i: 1
i: 2
i: 3
i: 4

How It Works

The register keyword is purely an advisory suggestion; the compiler can choose to ignore it if registers are full. Crucially, because register variables do not sit inside physical system RAM, you **cannot apply the address-of (&) operator** to them.

3. static Storage Class

A static variable preserves its value between consecutive function invocations. Unlike standard auto local variables, a static variable is initialized precisely once during program startup and retains its state throughout the entire execution lifetime.

Example Program
state_counters.c
C
#include <stdio.h>

void counter()
{
    static int count = 0; // Initialized ONLY once

    count++;

    printf("Count: %d\n", count);
}

int main()
{
    counter();
    counter();
    counter();

    return 0;
}
Console Output
Count: 1
Count: 2
Count: 3

How It Works

The variable count is allocated in the static data segment of RAM rather than the Stack. When counter() finishes executing, count does not get destroyed. The next call to counter() starts with the previously incremented value.

4. extern Storage Class

The extern keyword is used to access global variables defined in another compilation unit/file in the project. It declares a variable reference without allocating new memory.

Extern Syntax

Syntax
C
extern int shared_system_voltage; // Declares variable defined in another file

How It Works

An extern declaration merely states that a global variable with that exact name and type exists somewhere else. It acts as a linkage placeholder for the compiler, which the linker eventually resolves to point to the actual physical storage allocated in the primary file.

Memory Segment Allocation

When a C program is compiled and executed, the system organizes variables, instructions, and runtime data into different sections based on their scope, lifetime, and initialization behavior. Local variables (auto) are typically created inside the Stack during function execution, while global and static variables are stored inside the .data or .bss segments in RAM. Program instructions and constant data are stored separately inside the .text segment, usually located in FLASH or program memory. This organization allows the compiler and processor to manage execution efficiently and control how long data remains available during program runtime.

Storage Class Mapping

Keyword Memory Location Scope Lifetime
auto Stack Segment Local (Function) Until function exits
register CPU Register (if optimized) Local (Function) Until function exits
static .data or .bss Segment Local or File-Global Entire program execution
extern Reference to global variable Multi-file Global Entire program execution

Key Summary

  • Stack Segment — Temporary storage for local variables during function execution
  • .data / .bss Segments — Store initialized and uninitialized global or static variables
  • .text Segment — Contains compiled machine instructions and read-only constants
  • CPU Registers — Small high-speed processor storage used for temporary operations
  • extern — References a variable defined elsewhere instead of creating new storage

Embedded Focus

Storage classes are extremely important in embedded systems because firmware often interacts directly with hardware registers, device drivers, interrupts, and persistent system states. Proper variable placement helps control execution behavior, preserve critical data across function calls, and organize low-level hardware access cleanly across multiple source files.

hardware_states.c
C
// static keeps hardware state persistent and file-local
static int system_power_level = 100;

// extern shares hardware register access across files
extern volatile unsigned int *GPIOPortARegister;

Understanding where variables are stored becomes essential when working with microcontrollers, bootloaders, real-time systems, and memory-mapped peripherals.

← Chapter 15: Union and Enum Chapter 17: Dynamic Memory →