liveBook · Manning

Automatic storage

As explained in Modern C

Automatic storage duration is a C storage duration in which an object's lifetime is associated with execution of its defining block, except for variable-length arrays and temporary objects.

A local object

Consider `int main(void) { int x = 2; { int y = x + 1; x = y; } return x; }`. The inner block can use `x`, which belongs to the enclosing block. Its own `y` exists while that inner block executes. After the closing brace, `y` can no longer be used. section 13.2.2

The ordinary local variables `x` and `y` have automatic storage duration: their lifetimes are determined at runtime by execution of their defining blocks. Block-scope variables have this duration by default unless declared `static`; `auto` and `register` also designate it. Block-scope compound literals and some temporary objects returned by function calls are automatic too. section 13.2.2

TAKEAWAY: Except for variable-length arrays (VLAs) and temporary objects, an automatic object's lifetime corresponds to execution of its defining block. Each recursive call creates a separate local instance. An object cannot be accessed outside its lifetime; attempting to do so has undefined behavior. section 13.2.2 section 13.2

Listing 13.1. An example of shadowing with local variables
 1     void squareIt(double* p) {
 2       *p *= *p;
 3     }
 4     int main(void) {
 5     double x = 35.0;
 6     double* xp = &x;
 7     {
 8       squareIt(&x);  /* Refers to double x */ 
 9       ...
10       int x = 0;     /* Shadow double x */ 
11       ...
12       squareIt(xp);  /* Valid use of double x */ 
13       ...
14     }
15     ...
16     squareIt(&x);    /* Refers to double x */ 
17     ...
18   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":1},{\"line\":0,\"ch\":2}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":1}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":1}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":1}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":1}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":1}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":1}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":1}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":1}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":1}],[{\"line\":0,\"ch\":7},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":16},{\"line\":3,\"ch\":20}],[{\"line\":0,\"ch\":21},{\"line\":0,\"ch\":27}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":13}],[{\"line\":7,\"ch\":37},{\"line\":7,\"ch\":43}],[{\"line\":9,\"ch\":34},{\"line\":9,\"ch\":40}],[{\"line\":11,\"ch\":40},{\"line\":11,\"ch\":46}],[{\"line\":15,\"ch\":37},{\"line\":15,\"ch\":43}],[{\"line\":1,\"ch\":1},{\"line\":1,\"ch\":2}],[{\"line\":11,\"ch\":1},{\"line\":11,\"ch\":2}],[{\"line\":2,\"ch\":1},{\"line\":2,\"ch\":2}],[{\"line\":4,\"ch\":18},{\"line\":4,\"ch\":19}],[{\"line\":12,\"ch\":1},{\"line\":12,\"ch\":2}],[{\"line\":3,\"ch\":1},{\"line\":3,\"ch\":2}],[{\"line\":13,\"ch\":1},{\"line\":13,\"ch\":2}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":10}],[{\"line\":9,\"ch\":9},{\"line\":9,\"ch\":12}],[{\"line\":3,\"ch\":11},{\"line\":3,\"ch\":15}],[{\"line\":0,\"ch\":7},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":16},{\"line\":3,\"ch\":20}],[{\"line\":4,\"ch\":1},{\"line\":4,\"ch\":2}],[{\"line\":14,\"ch\":1},{\"line\":14,\"ch\":2}],[{\"line\":0,\"ch\":21},{\"line\":0,\"ch\":27}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":13}],[{\"line\":7,\"ch\":37},{\"line\":7,\"ch\":43}],[{\"line\":9,\"ch\":34},{\"line\":9,\"ch\":40}],[{\"line\":11,\"ch\":40},{\"line\":11,\"ch\":46}],[{\"line\":15,\"ch\":37},{\"line\":15,\"ch\":43}],[{\"line\":5,\"ch\":1},{\"line\":5,\"ch\":2}],[{\"line\":15,\"ch\":1},{\"line\":15,\"ch\":2}],[{\"line\":0,\"ch\":21},{\"line\":0,\"ch\":27}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":13}],[{\"line\":7,\"ch\":37},{\"line\":7,\"ch\":43}],[{\"line\":9,\"ch\":34},{\"line\":9,\"ch\":40}],[{\"line\":11,\"ch\":40},{\"line\":11,\"ch\":46}],[{\"line\":15,\"ch\":37},{\"line\":15,\"ch\":43}],[{\"line\":6,\"ch\":1},{\"line\":6,\"ch\":2}],[{\"line\":16,\"ch\":1},{\"line\":16,\"ch\":2}],[{\"line\":7,\"ch\":1},{\"line\":7,\"ch\":2}],[{\"line\":17,\"ch\":1},{\"line\":17,\"ch\":2}],[{\"line\":8,\"ch\":1},{\"line\":8,\"ch\":2}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":2}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":10}],[{\"line\":9,\"ch\":9},{\"line\":9,\"ch\":12}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":2}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":2}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":2}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":2}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":2}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":2}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":2}]]"}
!@%STYLE%@!

The inner `int x` hides the name of the outer `double x`, but a pointer saved before the inner declaration can still refer to the outer object. Shadowing a name does not end that object's lifetime. section 13.2

Lifetime and initialization are separate questions. Automatic objects must be initialized explicitly to put them in a well-defined state; unlike objects with static or thread storage duration, they receive no default initialization. section 13.4

A `register` declaration does not permit applying `&` to the variable. For a non-array local variable, this can expose address-taking that may limit optimization; it does not promise placement in a hardware register. Arrays need separate care because they commonly decay to an address. section 13.2.2

How Modern C covers it

How deep it goes
Defines categories and block lifetimes, explains recursive instances and register restrictions, and sets VLAs and temporary-object lifetimes apart.
Examples
Uses shadowed local variables and a saved pointer to separate identifier visibility from object lifetime.
What it assumes
Assumes familiarity with C blocks, local declarations, pointers, and function calls; defines storage duration and lifetime in context.
What you can do after
Diagnose/debug with it by checking whether a local object's lifetime has ended and whether it was explicitly initialized.
How it connects
Relates automatic storage to object lifetime, block scope, recursion, initialization, variable-length arrays, and aliasing.

Also explained in

Compare how 2 books explain automatic storage →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.