CStorage Classes (auto/static/extern/register)

Storage Classes (auto / static / extern / register)

Every variable in C has a storage class, which controls two things: where it lives in memory and how long it lives (its storage duration), and which parts of the program can see it (its linkage). C has four storage-class keywords: auto, static, extern, and register.

auto — the default, rarely written explicitly

Every local variable you've written so far has actually been auto by default — it's the automatic, implicit storage class for variables declared inside a function or block, so nobody writes it out:

C
void greet(void) {
    auto int count = 0; /* legal, but nobody writes "auto" -- it's implied */
    int total = 0;       /* identical meaning -- auto is the default */
}
This is NOT C++11's auto
If you've seen C++11 or later, `auto` there means *type inference* ("let the compiler figure out the type"). In C, `auto` has always meant something completely different — it's just the name of the default storage-class keyword, unrelated to type deduction. C has no type-inference keyword.
static — persists across function calls

A static local variable is initialized only once and then keeps its value between calls to the function, instead of being recreated every time:

C
#include <stdio.h>

int next_id(void) {
    static int counter = 0; /* initialized once, ever */
    counter++;
    return counter;
}

int main(void) {
    printf("%d\n", next_id()); /* 1 */
    printf("%d\n", next_id()); /* 2 */
    printf("%d\n", next_id()); /* 3 */
    return 0;
}
1
2
3

Compare that with an ordinary auto local, which resets to its initializer every call:

C
int not_counting(void) {
    int counter = 0; /* recreated fresh every call */
    counter++;
    return counter;
}
/* not_counting() always returns 1, no matter how many times it's called */

static has a second, unrelated-looking use: at file scope (outside any function), it gives a global variable or function internal linkage — meaning it's only visible within that source file, and other .c files in the same program can't reference it even with extern:

C
static int internal_cache_size = 128; /* only visible in this .c file */

static void helper(void) {            /* only callable from this .c file */
    /* ... */
}
extern — refers to a definition elsewhere

extern tells the compiler "this variable or function exists, but it's defined somewhere else — trust me and don't allocate storage for it here." It's how you share a global variable or function across multiple source files:

config.c

C
int app_version = 3; /* the one real definition, allocates storage */

main.c

C
#include <stdio.h>

extern int app_version; /* declaration only -- refers to config.c's variable */

int main(void) {
    printf("Version: %d\n", app_version);
    return 0;
}
Function prototypes are implicitly extern
You've been using `extern` implicitly all along: an ordinary function prototype like `int add(int a, int b);` in a header file is `extern` by default, which is why you can declare a function in one file and define it in another without writing the keyword yourself.
register — a hint to the compiler

register suggests that a variable will be used heavily and asks the compiler to keep it in a CPU register instead of ordinary memory, for faster access. A variable declared register cannot have its address taken with &.

C
int sum_to(int n) {
    register int i;
    register int total = 0;
    for (i = 1; i <= n; i++) {
        total += i;
    }
    return total;
}
register is mostly a historical relic today
Modern optimizing compilers are far better than most programmers at deciding which variables belong in registers, and they routinely ignore the `register` hint entirely — it's legal for a compiler to treat `register` as a no-op. The keyword is still recognized for backward compatibility, but writing it in new code rarely changes generated machine code and is generally considered outdated style.
Summary

Keyword

Typical use

Effect

auto

Local variables (default, rarely written)

Automatic storage duration -- recreated each call/block entry

static

Local variable that must persist, or file-scope internal linkage

Retains value across calls; or restricts visibility to one file

extern

Sharing a global across multiple .c files

Refers to a definition that exists elsewhere -- no storage allocated here

register

A rarely-needed optimization hint (mostly historical)

Suggests keeping the variable in a CPU register; compilers may ignore it