Storage

Overview

C objects can be annotated with storage class specifiers. These are used to adjust the object's storage duration and/or linkage.

Storage Durations

There are four different storage durations recognized in C: static, thread, automatic, and allocated.

Static

Objects with a static storage duration have a lifetime that span the entirety of the program execution. Such objects are always initialized, prior to program startup.

Thread

An object whose identifier is declared with the storage class specifier thread_local has thread storage duration. Its lifetime is the entire execution of the thread for which it is created, and its stored value is initialized when the thread is started.

Refer to TLS.

Automatic

Within a block, a variable or compound literal has automatic storage duration if it is declared without a storage class or with any of auto, constexpr, or register. Additionally, some temporary objects returned by function calls have automatic storage durations.

For objects that do not have a VLA type, their lifetime extends from entry into its enclosing block until execution of that block ends. Their initial values are indeterminate. If initialization is specified, it is performed each time the declaration or compound literal is reached in the execution of the block.

For objects that do have a VLA type, their lifetime extends from their declaration until execution of the program leaves the scope of the declaration.

Temporary

A non-lvalue expression with structure or union type, where the structure or union contains a member with array type refers to an object with automatic storage duration and temporary lifetime. Its lifetime lasts for the duration of the expression evaluation it is found within.

Allocated

The <stdlib.h> header provides the two most prominent functions used for managing dynamic memory: malloc and free. The former is used to allocate new memory whereas the latter is used to annihilate it.

void* malloc(size_t size);
void free(void*);

Dynamically allocated objects have allocated storage duration. Their lifetime spans from allocation to explicit destruction.

Storage Classes

Prior to C23, there exist six different storage class specifiers: typedef, auto, static, extern, thread_local (_Thread_local), and register. C23 added the constexpr storage class specifier.

typedef

The typedef storage class specifier is used to create alternative names for types. It is considered a storage class specifier primarily for syntactic convenience only. The standard library typically denotes typedef identifiers with an underscore _t.

auto

The auto storage class specifier is rarely used. As of C23, the same keyword is used for type inference.

static

The static storage class specifier indicates an identifier has internal linkage.

extern

The extern storage class specifier indicates an identifier (usually) has external linkage.

thread_local

The thread_local storage class specifier indicates an object has thread storage duration. Before C23, thread_local was instead a macro, provided by <threads.h>, corresponding to keyword _Thread_local.

register

The register storage class specifier declares an object with automatic storage duration. The & operator is not allowed on variables declared with register. This means such variables cannot alias.

Because of array-to-pointer decay, arrays with storage-class register are essentially useless.

constexpr

The constexpr storage class specifier indicates a value should be fixed at compilation. If not present, the const qualifier is implicitly added to the object's type.

Powered by Forestry.md