Storage Classes in C: Worked Examples for Scope, Lifetime, Linkage and GATE Traps
Learn what auto, register, static and extern actually control. Classification tables, two-file code and exact traces turn similar-looking declarations into predictable C behaviour.
KnowledgeGate Team
Exam prep & CS education

static may name a block-scoped object that survives calls or a file-scoped object hidden from other files. extern may declare a name without defining another object. Classify each declaration by scope, storage duration and linkage, then trace the calls to obtain 5 5 7, 5 8 8 and 5 11 9.
Storage classes in C: scope, storage duration and linkage
Three separate questions organise this topic:
Scope: Where can this name be used in the source text?
Storage duration: How long does the object exist? Learners often call this lifetime.
Linkage: Do declarations in the same or different translation units denote the same entity?
Declaration context matters, so a keyword alone cannot answer all three questions.
Exact declaration | Scope | Storage duration | Linkage |
|---|---|---|---|
| Block | Automatic | None |
| Block | Automatic | None |
| Block | Static | None |
| File | Static | Internal |
| File | Static for the referred object | External |
The final row refers to the single object defined in another file. auto, register, static and extern are the four conventional runtime-focused storage classes. C grammar also classifies typedef as a storage-class specifier, while C11 added _Thread_local for per-thread storage.

auto and register: automatic objects without the folklore
A block-scope object is automatic by default. Therefore, int a = 2; and auto int a = 2; have the same storage duration. Each execution of the block creates a fresh a; it starts at 2, becomes 5, then ceases to exist when execution leaves.
register int r = 4; also has block scope, automatic storage duration and no linkage. register is only an access-speed hint. An implementation need not put r in a CPU register, but C still does not permit &r.
This deterministic check prints 6:
register int r = 4;
auto int a = 2;
printf("%d\n", r + a);Do not extend that predictability to int x; without an initializer. An uninitialised automatic integer has an indeterminate value. It is not automatically zero, and no guessed numeric output is valid.
static in C: retained local state versus internal linkage
Inside a function, static int s = 2; gives s block scope and no linkage, but the object has static storage duration and is initialised only once. At file scope, static int hidden = 4; instead gives the name internal linkage. Another source file cannot name that same object.
Consider int next(void) { static int n = 10; n += 2; return n; }. Three calls return 12, 14 and 16. Replace the declaration with int n = 10;, and all three calls return 12 because each call creates a new automatic object.
Objects with static storage duration are initialised before program start. Without an explicit initializer, arithmetic objects are zero-initialised. Thus, file-scope int total; and block-scope static int hits; both begin at 0. Block-scope automatic int temp; remains indeterminate until assigned.
extern in C: one definition shared across source files
Suppose counter.c contains:
int total = 12;
static int hidden = 4;
int add(int x) {
total += x;
return total;
}Now main.c contains extern int total; and int add(int);. Printing total first gives 12. After int result = add(5);, printing result and total gives 17 17.
extern int total; refers to the object defined once in counter.c; it does not create a second total. The linker resolves that external-linkage name across translation units. If main.c instead declares extern int hidden; and uses it, no external definition matches because the hidden in counter.c has internal linkage. Linking fails.
Keep the declaration and definition boundary exact. Here, extern int total; without an initializer is a declaration, while int total = 12; is the definition. An extern declaration with an initializer is itself a definition, so the shortcut “extern never defines storage” is false.
Worked storage-class trace: auto resets, static retains, global state changes
Trace this program statement by statement:
#include <stdio.h>
int g = 7;
void tick(void) {
auto int a = 2;
static int s = 2;
a += 3;
s += 3;
printf("%d %d %d\n", a, s, g);
g++;
}
int main(void) {
tick();
tick();
tick();
return 0;
}On call 1, new a goes from 2 to 5. The once-initialised s goes from 2 to 5. The program prints g as 7, then increments it to 8. The first line is 5 5 7.
On call 2, another new a becomes 5. Retained s goes from 5 to 8. The program prints g as 8, then increments it to 9. The second line is 5 8 8.
On call 3, a again becomes 5, retained s goes from 8 to 11, and g prints as 9 before becoming 10. The third line is 5 11 9.
5 5 7
5 8 8
5 11 9So a has block scope, automatic duration and no linkage. s has block scope, static duration and no linkage. File-scope g has static duration and external linkage by default.

Storage-class traps: initialization, shadowing and invalid assumptions
Mistake: “static means global.” Consequence: A block-scope static is misclassified. Correction: It keeps block scope but has static duration.
Mistake: “extern creates a copy.” Consequence: A two-file trace gains two imagined totals. Correction: The declaration refers to one externally linked definition.
Mistake: “uninitialised objects are zero.” Consequence: Code reads an indeterminate automatic
int x. Correction:static int s;and file-scopeint g;begin at0, but block-scope automaticint x;must be assigned before reading.
Shadowing is separate. With file-scope int x = 9;, a function that declares int x = 3; prints 3 inside that block. The outer object remains 9. Shadowing changes which declaration the name denotes, not either object's storage duration.
Two more checks catch common exam traps. register int r = 4; int *p = &r; violates the address rule for a register object. extern int missing; may compile when used, but linking fails if the program provides no definition.
How GATE-style questions test storage classes in C
GATE-style tasks classify declarations, trace repeated calls with a block static, compare zero-initialised static-duration objects with indeterminate automatic ones, follow one external object across files, and distinguish compile-time constraints from link failures.
Try a 60-second drill: change static int s = 2; to static int s = 1; and call tick() four times. a stays 5; s becomes 4, 7, 10, 13; g prints 7, 8, 9, 10. The lines are 5 4 7, 5 7 8, 5 10 9 and 5 13 10.
IIT Guwahati's GATE 2026 Computer Science and Information Technology syllabus places “Programming in C” in Section 4. That scope statement does not imply a fixed mark share or yearly frequency. The definition-first reference table and short exam questions belong to Storage Classes in C (auto, static, extern, register): Scope, Lifetime and Exam Questions. The two-file extern case and three-call state trace train execution instead. Use the GATE CS Exam category for broader preparation and MCQ, MSQ or NAT? GATE Question Types Explained for answer-format technique.
Storage classes in C: the short version and next step
Use a four-part routine: find the declaration context, mark the name's scope, mark the object's automatic or static duration, then decide whether linkage is none, internal or external. In the trace, a resets to 2, s retains its prior value, and externally linked g advances from 7 to 10 after three calls.
For a compact language-first route, use the C Programming course. For a broader GATE sequence containing C Language, Storage Classes, Structures and Enums, use GATE Guidance by Sanchit Sir. They are alternative starting points, so choose the route that matches your present goal.
Keep learning

Functions in C: Syntax, Parameters and Worked Examples
Learn how C declarations, calls, and definitions fit together. Compile two complete programs, follow their values, and trace composition and recursion.

Smart Pointers in C++: unique_ptr, shared_ptr and weak_ptr with Worked Examples
Learn who owns a C++ object, when it is destroyed, and how to choose among unique_ptr, shared_ptr, weak_ptr and a borrowed raw pointer.

Pointers in C: Addresses, Arrays and Functions with Worked Examples
Build a practical pointer model with runnable C programs for dereferencing, arrays, swapping, dynamic memory and common tracing questions.

Pointers and Arrays in C: Decay, Indexing and Worked Examples
Separate arrays from pointers with runnable traces covering indexing, one-past boundaries, function parameters, two-dimensional arrays and declaration traps.