Skip to content

Chapter 17 of 21

Storage Classes

Reason about scope, linkage, and lifetime with auto, static, extern, and register.

26 minutes 10 quick checksBy Subha Prasad
Lesson 17 of 21Course navigation

Lesson content

Read, practise, then check your understanding

Storage-class specifiers help describe an identifier’s storage duration and linkage. These concepts are distinct:

  • Scope: where the name is visible.
  • Storage duration: how long its object exists.
  • Linkage: whether declarations in different scopes or translation units name the same entity.

auto

Block-scope variables are auto by default. They have automatic storage duration: their lifetime begins when execution enters the block and ends when it leaves.

void process(void) {
    auto int attempts = 0; // explicit auto is valid but rarely written
}

An uninitialized automatic object has an indeterminate value.

static

At block scope, static gives static storage duration while retaining block scope. Initialization occurs once before normal program execution, and the value persists across calls.

unsigned next_id(void) {
    static unsigned current = 0;
    return ++current;
}

This function is not thread-safe without synchronization and hides global state behind a narrow scope.

At file scope, static gives a name internal linkage, keeping a function or object private to its translation unit:

static void normalize_record(struct Record *record);
static const int default_limit = 100;

extern

extern declares an object or function defined elsewhere. Put one declaration in a header and exactly one object definition in a source file.

// metrics.h
extern unsigned long request_count;

// metrics.c
unsigned long request_count = 0;

Prefer accessor functions over exported mutable global objects when invariants or concurrency matter.

register

register historically suggested fast register storage for an automatic variable and prevents taking its address. Modern optimizers perform register allocation better than manual hints; the specifier is obsolete or removed in newer language evolution and should generally be avoided.

Thread storage

C11 provides _Thread_local for one instance per thread, subject to implementation support. Thread-local state can simplify context access but complicates testing and lifecycle reasoning.

Choose storage based on required lifetime and visibility, not convenience. Narrow scope and internal linkage reduce accidental coupling.

Knowledge check

Answer every question correctly to complete this chapter.

What lifetime does a local static variable have?
What does extern usually declare?
What is the default storage duration of an ordinary block-scope variable?
How is an uninitialized static-duration integer initialized?
What does static give a file-scope function name?
Where is a block-scope static variable’s name visible?
How many object definitions should normally back one extern declaration?
Why is register rarely useful with modern compilers?
Can code take the address of an object declared register?
What does _Thread_local provide?

0 of 10 checks passed

Your progress is saved on this device.

Storage Classes | C Lesson | Subha Prasad