Overview
An object has a storage duration that determines its lifetime. There are four storage durations: static, thread, automatic, and allocated.
Static
An object whose identifier is declared without storage-class specifier _Thread_local
, and either with external or internal linkage or with the storage-class specifier static
, has static storage duration.
Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup. Initialization always happens.
Thread Local
An object whose identifier is declared with the storage-class specified _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.
Automatic
An object whose identifier is declared with no linkage and without the storage-class specifier static
has automatic storage duration, as do some compound literals.
For these objects that do not have a VLA type, its lifetime extends from entry into its enclosing block until execution of that block ends. Its initial value is indeterminate. If initialization is specified, it is performed each time the declaration or compound literal is reached in the execution of the block.
For these objects that do have a VLA type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.
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.
Register
In contrast to auto
, there also exists a register
storage-class specifier. The &
operator is not allowed for variables declared with register
meaning variables declared with register
can’t alias.
Because of array-to-pointer decay, arrays with storage-class register
are useless.
Dynamic Allocation
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.
Dynamically allocated objects have allocated storage duration. Their lifetime spans allocation to explicit destruction.
Storage-Class Specifiers
Storage-class specifiers are used to control an object’s storage duration and an identifier’s linkage. There are six storage-class specifiers:
typedef
- Discussed in typedefs.
- Is called a “storage-class specifier” for syntactic convenience only.
extern
static
_Thread_local
- Discussed in Thread Local.
auto
- Discussed in Automatic.
register
- Discussed in Automatic.
At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that _Thread_local
may appear with static
or extern
.
Bibliography
- “ISO: Programming Languages - C17,” April 2017, https://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf.
- Jens Gustedt, Modern C (Shelter Island, NY: Manning Publications Co, 2020).