[C Series 16] Reading Variable Lifetimes through Storage Duration and Scope

한국어 버전

If part 15 helped you prepare code with the preprocessor, it's time to dissect the question "When is a variable created, and when does it disappear?" In C, variables that share the same name can have completely different lifetimes depending on their storage duration and scope. Add linkage to the mix, and you must separately reason about "How long does it stay alive?", "Where is it visible?", and "Does the same name connect across translation units?" A translation unit is roughly one .c file after the preprocessor has expanded its headers. Mastering this flow prevents the misuse of globals and keeps sharing variables between different .c files from becoming chaos.

New Terms in This Lesson

  1. Storage Duration: How long the value stays in memory
  2. Automatic Storage: The lifetime of local variables that vanish once you leave the block
  3. Static Storage: Variables that live for the entire program run
  4. Scope: The region of code where a name can be referenced

Key Ideas

Study Notes

  • Estimated time: 60 minutes
  • Prereqs: Functions, preprocessing, header/source separation
  • Goal: Use static and extern to control storage duration, and distinguish block/file scope

Storage duration and scope must be discussed together.

  • Storage duration describes how long the backing memory remains alive. The main categories are automatic, static, and dynamic.
  • Scope describes the region of code that can refer to that name.
  • Linkage captures whether the same name points to the same entity from other files.

They are not always synchronized. A static variable inside a function has static storage duration (kept for the entire program) but scope limited to that function. So far, most variables have lived inside one function. What if you need a variable to remain available across calls, or even across files? That is where file scope, linkage, and extern begin to matter. This article covers:

  • Automatic variables and block scope
  • Global variables and file scope
  • Internal linkage via the static keyword
  • Reaching for global variables from other files with extern
  • Examples and tips for static locals

Code Walkthrough

Automatic Storage and Block Scope

#include <stdio.h>

int main(void) {
    int count = 0; // automatic storage duration

    if (1) {
        int count = 10; // new block scope
        printf("block count = %d\n", count);
    }

    printf("outer count = %d\n", count);
    return 0;
}

Declaring the same name inside the if block gives it a brand-new lifetime that ends once the block finishes. Automatic variables release their storage when the function returns, so do not hand out their addresses.

Global Variables and File Scope

#include <stdio.h>

int g_total = 0; // file scope + static storage duration

void add_score(int value) {
    g_total += value;
}

int main(void) {
    add_score(10);
    add_score(5);
    printf("total = %d\n", g_total);
    return 0;
}

File-scope variables can be referenced anywhere below their declaration and keep their value for the entire run. Still, global variables increase coupling, so prefer passing data through parameters or structs unless a global truly makes sense.

Using static for Internal Linkage

// counter.c
#include <stdio.h>

static int internal_total = 0; // hidden from other translation units

void increase(void) {
    internal_total++;
    printf("internal_total = %d\n", internal_total);
}

Adding static to a file-scope variable or function gives it internal linkage, so the symbol does not participate in linking from other translation units. It is useful when you want to keep internal state or helper functions off the public header surface.

static changes slightly based on context:

  • File scope static: hides the symbol from other files
  • Function-scope static: keeps the value alive even after the function returns

Static Local Variables

#include <stdio.h>

void greet(void) {
    static int called = 0; // static storage + block scope
    called++;
    printf("greet called %d times.\n", called);
}

int main(void) {
    greet();
    greet();
    greet();
    return 0;
}

Static locals preserve their value across calls. Use them for call counters, caches, or lazy initialization. Just remember to guard against concurrent access in multithreaded code.

Reaching External Variables with extern

// config.c
int g_mode = 1;

// main.c
#include <stdio.h>

extern int g_mode; // declared, not defined, in this file

int main(void) {
    if (g_mode == 1) {
        printf("standard mode\n");
    }
    return 0;
}

An extern declaration says "This variable is defined elsewhere; treat this as a reference to it." The declaration itself does not allocate new storage. Instead, it points to a definition that must exist in exactly one translation unit. The usual pattern is to put extern declarations in headers and keep the single definition in a .c file.

Storage Duration Cheat Sheet

Storage duration Keyword/example Lifetime Scope sample
Automatic Inside a function Until the block ends Block scope
Static Globals, static locals Entire program File or block scope
Dynamic malloc/free Until free Wherever the pointer travels

Keep this table in mind so that every time you declare a variable, you also ask "Who holds onto it, and until when?"

Why It Matters

  • Understanding storage duration prevents memory bugs and uncontrolled global state.
  • static and extern help set module boundaries and encapsulate state.
  • As you move toward function pointers and build automation, a firm grasp of variable lifetimes shortens debugging time.

Practice in CodeSandbox

The sandbox below uses CodeSandbox's Universal starter. For C, the key learning loop is still compile and run in the terminal, so recreate the lesson code as a source file and repeat that cycle directly.

Live Practice

C Practice Sandbox

CodeSandbox

Run the starter project in CodeSandbox, compare it with the lesson code, and keep experimenting.

Universal starterCterminal
  1. Fork the starter and create a practice file such as hello.c
  2. Paste in the lesson code and compile it if clang or gcc is available
  3. Edit the code, rebuild it, and compare the new output

For C, the terminal build loop matters more than a browser preview. Compiler availability can vary by environment, so first confirm that clang or gcc is present in the Universal starter.

Practice

  • Follow along: Write a program that counts function calls with static locals and confirm each function keeps its own counter.
  • Extend: Move an extern declaration into a header and let two .c files share the same global variable during a build.
  • Debug: Shadow a global by declaring a local with the same name and print the values to see the effect.
  • Completion check: Be able to explain the differences between automatic, static, and dynamic storage duration and the roles of static and extern in one paragraph.

Wrap-Up

Clear mental models for variable lifetime and visibility keep state manageable as your program grows. Review memory, preprocessing, and storage duration now, and the upcoming topics—function pointers and build automation—will click much faster.

💬 댓글

이 글에 대한 의견을 남겨주세요