๐Ÿ’พ 22. Storage Classes in C

A storage class in C helps describe important properties associated with an identifier, such as its scope, storage duration, and, where relevant, linkage.

Use this lesson to answer three questions about a variable: where can its name be used, how long does its object exist, and can declarations in other files refer to the same object?

Core idea: The examples use C17 rules and focus on auto, register, static, and extern. These keywords do not simply name physical RAM locations. Keep scope, storage duration, and linkage separate.

22.1 Why Storage Classes Matter

Consider these two variables:

int local = 10;

and:

static int count = 0;

Both are integers, but their behavior can be very different.

  • A normal local variable generally has automatic storage duration.
  • A static local variable retains its stored value between function calls.
  • An external declaration can refer to an object defined elsewhere.
  • register expresses a request to keep an object in a register when supported by the implementation, but it does not guarantee this.

22.2 The Four Traditional Storage-Class Specifiers

Specifier Typical Context Important Property
auto Block-scope local variables Automatic storage duration
register Block-scope objects / parameters in applicable declarations Requests register storage; implementation may ignore the request
static Block scope and file scope Static storage duration; file-scope use also affects linkage
extern Declarations referring to externally defined objects/functions Declares an identifier without necessarily defining the object
Important: The meaning of static depends on where it appears. A block-scope static object and a file-scope static object both have static storage duration, but their visibility/linkage behavior is different.

22.3 Scope, Lifetime, Storage Duration and Linkage

These terms are often mixed together. They describe different properties.

Scope

Where in the source can this name be used to refer to its declaration?

Storage Duration

How long does the objectโ€™s storage exist?

Linkage

Can declarations in different scopes or source files refer to the same object or function?

22.4 The Four Storage Durations

Storage Duration Meaning Typical Example
Automatic Storage exists for execution of the relevant block. Ordinary local variable
Static Storage exists for the entire execution of the program. Global or static local object
Allocated Storage is obtained dynamically and lasts until released or otherwise ceases to be available. malloc()-allocated object
Thread Storage duration associated with a thread. _Thread_local

Allocated storage duration is covered more deeply in the Dynamic Memory Allocation topic. Thread storage duration is an advanced C feature and is outside the main focus of this lesson.

22.5 The auto Storage Class

The auto specifier indicates automatic storage duration for an object declared at block scope.

int main(void) { auto int x = 10; printf("%d\n", x); return 0; }

In ordinary modern C programming, the keyword auto is usually omitted for ordinary local variables. This section uses its traditional C17 meaning. C23 also supports type inference with auto, which is a separate newer use.

22.6 Automatic Variables

This is more common:

int main(void) { int x = 10; printf("%d\n", x); return 0; }

Here x is an automatic-duration object because it is an ordinary block-scope local variable.

Remember: An automatic local variable is not filled with zero just because the block begins. Initialize it before reading its value.

22.7 Example of Automatic Lifetime

void demo(void) { int x = 10; printf("%d\n", x); }

Each time demo() is entered, a new instance of the automatic object x is created for that execution of the block. Its storage duration ends when execution leaves the block.

22.8 Automatic Variables and Initialization

int main(void) { int a; int b = 20; printf("%d\n", b); return 0; }

b has a specified initial value. a does not. Reading a before assigning a valid value is a mistake. A local declaration without an initializer is not a request to start the object at zero.

22.9 The register Storage Class

The register keyword historically expresses a request that an object be stored in a processor register if possible.

int main(void) { register int i; for (i = 0; i < 10; ++i) { printf("%d ", i); } return 0; }
Modern compilers perform their own optimization decisions. Writing register does not guarantee that the object will actually reside in a hardware register.

22.10 Important Rule About register

A particularly important language rule is that you cannot apply the unary address-of operator to an object declared with the register storage-class specifier.

register int x = 10; /* Not allowed: */ int *p = &x;

The language specifically restricts taking the address of a register-declared object.

22.11 Should You Use register Today?

Write clear code and measure performance when needed. The compiler can choose registers without a register declaration.

The keyword remains part of the language, so it is still important for exams and for understanding older C code.

22.12 The static Storage Class

The keyword static has two especially important uses:

  1. At block scope, it gives the object static storage duration.
  2. At file scope, it gives an object or function internal linkage.
This distinction is extremely important for interviews. Do not memorize "static means global." It does not.

22.13 Static Local Variable

void counter(void) { static int count = 0; count++; printf("%d\n", count); }

If called three times:

counter(); counter(); counter();

the output is:

1 2 3

The local name count remains visible only inside the function, but the object retains its value between calls.

22.14 Static Local Variable Trace

 First call | โ–ผ count = 0 | โ–ผ count++ | โ–ผ prints 1 Second call | โ–ผ same static object | โ–ผ count = 1 | โ–ผ count++ | โ–ผ prints 2 Third call | โ–ผ count = 2 | โ–ผ count++ | โ–ผ prints 3 

22.15 Static Local vs Normal Local

Property Normal Local Static Local
Scope Block Block
Storage duration Automatic Static
Retains value between calls? No Yes
Initialized when? Each entry/creation as applicable Once before program startup
Default initialization Indeterminate if no initializer Zero-initialized if no explicit initializer

22.16 Static Local Initialization

void demo(void) { static int x = 10; x += 5; printf("%d\n", x); }

Repeated calls produce:

15 20 25 

The static initializer is applied once. Later calls continue with the stored value left by earlier calls; they do not restart it from the initializer.

22.17 Static Local Variables in Recursion

During recursion, distinguish a new automatic variable in each call from a single static variable shared by the calls.

void countDown(int n) { static int calls = 0; calls++; if (n > 0) { countDown(n - 1); } printf("Calls = %d\n", calls); }

All recursive invocations refer to the same static object calls, not separate copies.

Each active call normally has its own automatic locals. All calls to the function use the same static local object, so a change in one call is visible to later calls.

22.18 Static at File Scope

Consider:

static int counter = 0;

At file scope, this object has static storage duration and internal linkage.

The file-scope name has internal linkage. Another source file cannot use an ordinary extern declaration of that name to refer to this object. This restricts name linkage, not every possible access through a pointer.

22.19 Static File-Scope Function

static void helper(void) { printf("Internal helper\n"); }

A file-scope function declared static has internal linkage. Other translation units cannot refer to it through an ordinary external declaration of the same name. It is useful as a private helper within a module.

22.20 Why File-Scope Static Is Useful

  • Hides implementation details from other source files.
  • Reduces accidental name collisions across translation units.
  • Helps create private helper functions and private file-level objects.
  • Makes module boundaries clearer.

22.21 Internal vs External Linkage

Linkage Meaning
None A local variable normally has no linkage. A matching name in another block does not automatically refer to that same local object.
Internal Declarations in the same translation unit can refer to the same entity.
External Declarations in different translation units can refer to the same entity when the linkage rules allow it.

22.22 What Is a Translation Unit?

For this lesson, think of a translation unit as a source file after preprocessing, including the header contents selected by its include directives.

 source.c | | preprocessing v translation unit | | compilation v object file | | linking v executable 

22.23 The extern Storage Class

The extern keyword is commonly used to declare that an object or function is defined elsewhere.

Example:

extern int total;

This declaration says that total refers to a shared object. In this example there is no earlier declaration changing its linkage, so it has external linkage. Provide one matching definition in the program when it is used.

22.24 Declaration vs Definition

This distinction is critical when learning extern.

extern int total;

is normally a declaration that does not define the object.

Whereas:

int total = 100;

is a definition of the object.

Simple rule: A declaration introduces a name and type. An object definition provides its storage. At file scope, extern int total; normally declares without defining, while extern int total = 0; is a definition because it has an initializer.

22.25 Multi-File Example

counter.c

int total = 100;

main.c

#include <stdio.h>

extern int total;
int main(void) {
    printf("%d\n", total);
    return 0;
}

The definition of total is in one translation unit and its declaration is visible in the other.

22.26 Header Files and extern

In a multi-file project, an external declaration is often placed in a header.

config.h

#ifndef CB_CONFIG_H
#define CB_CONFIG_H
extern int total;
#endif

config.c

#include "config.h"
int total = 100;

main.c

#include <stdio.h>
#include "config.h"

int main(void)
{
    printf("%d\n", total);
    return 0;
}
Use the header to share the declaration, and put the matching definition in one source file. Source files that use the object include the header.

22.27 Do Not Define Ordinary Global Objects Repeatedly in Headers

A common mistake is putting an ordinary external definition directly into a header:

/* Bad header design */ int total = 100;

An include guard does not prevent this problem across translation units: each source file can still get its own external definition from the header. Use an extern declaration in the header and one definition in a source file.

A common pattern is:

/* header */ extern int total; /* exactly one .c file */ int total = 100;

22.28 Static vs Extern

Feature static at File Scope extern
Typical purpose Keep entity private to translation unit Refer to externally linked entity
Linkage Internal External
Common use Private helper function/object Shared declaration across source files

22.29 Static Function vs Normal Function

static void calculate(void) { /* private helper */ }

Compared with:

void calculate(void) { /* externally linked function */ }

At file scope, static gives the function internal linkage. A normal file-scope function definition normally has external linkage unless another rule changes it.

22.30 Static Does Not Mean Constant

Common mistake: Thinking static means "cannot change."

It does not.

static int count = 0; count++; count++; 

The value can change normally.

If you want an object that cannot be modified through its declared type, const is relevant.

22.31 Static Does Not Mean Global

Consider:

void demo(void) { static int x = 10; }

The name is still local to its block. The object survives between calls, but code outside that scope cannot use the local name directly.

22.32 Static Initialization

Objects with static storage duration are initialized before program startup according to C's initialization rules.

static int a; static int b = 20;

Without an explicit initializer, arithmetic members receive zero values and pointer members receive null pointer values according to their types. This is not a rule that every object is represented by all-zero bytes.

22.33 Automatic vs Static Initialization

Object No Explicit Initializer
int x; inside a function Indeterminate value; do not read it before giving it a valid value.
static int x; Initialized to zero.
File-scope int x; Initialized to zero.

22.34 Storage Class and Scope Are Different

Consider:

int global; void demo(void) { int local; static int persistent; }
Identifier Scope Storage Duration
global File Static
local Block Automatic
persistent Block Static

22.35 Storage Class and Memory Location

A beginner-friendly diagram might show:

 Program Memory โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ Static-duration Automatic Allocated objects objects objects โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ global/static local data malloc/calloc objects in blocks /realloc 

The diagram is a learning model. C specifies lifetime and linkage rules; it does not require every automatic object to be on a hardware stack or every static object to occupy a particular named memory segment.

22.36 Storage Classes and Functions

Storage-class specifiers also appear in function declarations and definitions, but their meaning must be interpreted according to context.

The most common example is:

static void helper(void) { }

where static at file scope gives the function internal linkage.

22.37 The extern Keyword With Functions

Functions normally have external linkage unless their declaration is made static.

Therefore an explicit:

extern void display(void);

can declare an externally linked function defined elsewhere.

Because external linkage is the normal case for ordinary file-scope functions, explicit extern is often unnecessary for function declarations.

22.38 Storage-Class Specifiers vs Type Qualifiers

Category Examples Purpose
Storage-class specifiers auto, register, static, extern Describe storage duration/linkage and related declaration properties.
Type qualifiers const, volatile, restrict, _Atomic Qualify the type or access semantics.
static and const are not interchangeable. One is a storage-class specifier; the other is a type qualifier.

22.39 What About _Thread_local?

Modern C also provides the _Thread_local storage-class specifier for objects whose storage duration is associated with a thread.

_Thread_local int thread_count;

Each thread can have its own instance of the object.

This is an advanced topic and is mainly relevant to multithreaded C programs.

22.40 Complete Comparison

Specifier Typical Scope Storage Duration Linkage Effect Typical Use
auto Block Automatic None Explicitly request automatic duration; rarely written.
register Block Automatic None Historical optimization hint; address cannot be taken.
static at block scope Block Static None Preserve local state between calls.
static at file scope File Static Internal Hide object/function within translation unit.
extern File/block declarations as applicable Usually refers to static-duration object/function External Declare an entity defined elsewhere.

22.41 Example โ€” Four Concepts Together

#include <stdio.h>

int global_value = 100;
static int private_value = 200;
void demo(void) {
    int local_value = 10;
    static int persistent_value = 0;
    persistent_value++;
    printf("%d %d %d %d\n", global_value, private_value, local_value, persistent_value);
}
int main(void) {
    demo();
    demo();
    return 0;
}

Important observations:

  • global_value has static storage duration and external linkage.
  • private_value has static storage duration and internal linkage.
  • local_value has automatic storage duration.
  • persistent_value has static storage duration but block scope.

22.42 Program Trace

 Program starts global_value = 100 private_value = 200 persistent_value = 0 | โ–ผ First demo() local_value = 10 persistent_value++ persistent_value = 1 Output: 100 200 10 1 | โ–ผ demo() ends local_value disappears persistent_value remains 1 | โ–ผ Second demo() new local_value = 10 persistent_value++ persistent_value = 2 Output: 100 200 10 2 

22.43 Why Does Static Local Remember?

The key is storage duration.

static int count = 0;

The object continues to exist after the function block finishes, even though the identifier count is only usable within that block.

 Scope โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ function block only Storage duration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ entire program execution Therefore: name is local object lifetime is persistent 

22.44 Static Local Counter Pattern

This is a common practical pattern:

int next_id(void) { static int id = 1000; return id++; }

Repeated calls return:

1000 1001 1002 1003 ...

The function keeps its own running state between calls. Because that state persists, repeated tests or concurrent calls need to account for earlier updates.

22.45 Static Function for Module Encapsulation

static int square(int x) { return x * x; }

If the function is defined at file scope with static, it is private to that translation unit in terms of linkage.

This is useful for helper functions that should not become part of a module's external interface.

22.46 A Typical Header/Source Design

student.h

#ifndef CB_STUDENT_H
#define CB_STUDENT_H

typedef struct { int id; char name[50]; } Student;
void printStudent(const Student *student);

#endif

student.c

#include <stdio.h>
#include "student.h"

static void printSeparator(void)
{
    printf("----------------\n");
}

void printStudent(const Student *student)
{
    printSeparator();
    printf("ID: %d\n", student->id);
    printf("Name: %s\n", student->name);
}

Here printSeparator() is a private helper because it is file-scope static.

22.47 Why This Design Is Useful

  • The header exposes the public interface.
  • The source file contains the implementation.
  • The static helper is hidden from other translation units.
  • Other files can use printStudent() through the header.

22.48 Common Storage-Class Mistakes

  • Thinking static always means global.
  • Thinking static means constant.
  • Thinking register guarantees a CPU register.
  • Thinking auto initializes local variables to zero.
  • Thinking extern creates the actual global object.
  • Defining the same external object in multiple source files.
  • Putting ordinary external variable definitions in widely included headers.
  • Confusing scope with storage duration.
  • Confusing storage duration with physical RAM location.
  • Assuming a static local variable becomes globally accessible.

22.49 Common Confusions

Confusion 1: "static variable is a global variable."

Correction: A block-scope static variable remains local in scope but has static storage duration.

Confusion 2: "extern creates a variable."

Correction: An extern declaration without an initializer normally refers to an existing object. At file scope, adding an initializer makes that declaration a definition.

Confusion 3: "register means the variable is definitely stored in CPU register."

Correction: It is a request/hint; the implementation decides actual storage and optimization.

Confusion 4: "static means immutable."

Correction: Static objects can be modified unless they are separately declared with appropriate type qualification such as const.

Confusion 5: "local variable is always zero."

Correction: An uninitialized automatic object has an indeterminate value.

22.50 Storage Classes and Recursion

Consider a normal recursive function:

void recurse(int n) { int local = n; if (n > 0) recurse(n - 1); }

Each active invocation has its own automatic local object.

With:

static int local;

there is one static object shared by all invocations of the function.

 Automatic recursion: Call 1 โ†’ local A Call 2 โ†’ local B Call 3 โ†’ local C Static recursion: Call 1 โ”€โ” Call 2 โ”€โ”ผโ”€โ”€โ–บ one static object Call 3 โ”€โ”˜ 

22.51 Storage Duration Is Not Stack/Heap Terminology

You may hear programmers say:

automatic = stack allocated = heap static = data segment 

These are useful implementation-level mental models, but they are not the complete language definition.

First identify scope, storage duration, linkage, and initialization. Then use implementation documentation if you need to know where the compiler actually places an object.

22.52 Interview Question โ€” static Local

#include <stdio.h>

void test(void) {
    static int x = 0;
    x++;
    printf("%d ", x);
}
int main(void) {
    test();
    test();
    test();
    return 0;
}

Output:

1 2 3

Reason: the same static object persists between calls.

22.53 Interview Question โ€” Automatic Local

#include <stdio.h>

void test(void) {
    int x = 0;
    x++;
    printf("%d ", x);
}
int main(void) {
    test();
    test();
    test();
    return 0;
}

Output:

1 1 1

The automatic local object is initialized to zero for each invocation.

22.54 Interview Question โ€” File-Scope static

static int count = 10;

At file scope, count has internal linkage. Another translation unit cannot access that object through an ordinary external declaration of the same identifier.

22.55 Interview Question โ€” extern

Suppose:

/* file1.c */ int value = 50;

and:

/* file2.c */ extern int value;

The second declaration allows code in file2.c to refer to the externally linked object defined in file1.c.

22.56 Interview Question โ€” register Address

register int x = 10; printf("%p", (void *)&x);

This is not valid C because the address of a register-declared object cannot be taken.

22.57 Storage Class Decision Tree

 Do you need ordinary local state? | โ”œโ”€โ”€ Yes โ†’ automatic object | โ–ผ Do you need local state to survive function calls? | โ”œโ”€โ”€ Yes โ†’ static local | โ–ผ Do you want a file-private object/function? | โ”œโ”€โ”€ Yes โ†’ file-scope static | โ–ผ Do you need to refer to an external definition? | โ”œโ”€โ”€ Yes โ†’ extern declaration | โ–ผ Do not use register merely to force optimization. Let the compiler optimize. 

22.58 Best Practices

  • Prefer ordinary local variables unless persistent local state is actually needed.
  • Use static locals deliberately when state should survive calls but remain encapsulated.
  • Use file-scope static to keep implementation details private to a source file.
  • Use headers for declarations and source files for definitions where appropriate.
  • Use extern for declarations of externally linked entities rather than duplicating definitions.
  • Do not depend on register for performance.
  • Do not describe storage classes solely as physical memory locations.

22.59 Thread-Local Storage โ€” an Advanced Storage Duration

Modern C distinguishes automatic, static, thread and allocated storage durations. _Thread_local was introduced in C11 (C23 also introduces the thread_local spelling). A thread-local object has one instance per thread and exists for that threadโ€™s lifetime.

Complete C program:

#include <stdio.h>

_Thread_local int perThreadCount = 0;

int main(void)
{
    ++perThreadCount;
    printf("Count = %d\n", perThreadCount);
    return 0;
}

Expected output:

Count = 1

Step-by-step explanation:

  1. The example uses a single thread so one instance of the variable exists.
  2. An additional thread would have a separate instance of the thread-local object.
  3. It is not shared like an ordinary global object.
Remember: A thread-local object gives each thread its own instance. It does not protect other shared variables or make an entire function safe for concurrent use.

22.60 Quick Revision

๐Ÿ“Œ auto โ†’ Default for ordinary local variables.

๐Ÿ“Œ register โ†’ Requests register-oriented optimization; compiler may ignore the request.

๐Ÿ“Œ static local โ†’ Retains value between function calls.

๐Ÿ“Œ static file-scope โ†’ Internal linkage.

๐Ÿ“Œ extern โ†’ Declares an object/function defined with appropriate linkage elsewhere.

๐Ÿ“Œ Scope โ†’ Where the name can be used.

๐Ÿ“Œ Lifetime โ†’ How long the object exists.

๐Ÿ“Œ Linkage โ†’ Whether declarations in different scopes/files can refer to the same entity.
INTERACTIVE LEARNING

๐ŸŽฌ Storage Classes โ€” Scope, Lifetime & Linkage

Compare the key idea behind auto, register, static, and extern.

PROGRAM TRACING

๐Ÿ”Ž Program Tracing โ€” Storage Classes

Compare an automatic local variable that is created for each call with a static local variable that retains its value between calls.

22.61 Quick MCQs

Select an answer first, then click Check Answer. A correct choice becomes green. If the answer is wrong, your choice becomes red and the correct option becomes green. The explanation appears below.

1. Which storage class is the default for ordinary local variables?
2. Which keyword allows a local variable to retain its value between function calls?
3. Which keyword declares a reference to an object defined elsewhere?
4. Which keyword can be used for a file-scope function to give it internal linkage?
5. An uninitialized static-duration int object is initialized to:
6. Which keyword does not guarantee that a variable will be stored in a CPU register?
7. A static local variable has:
8. Which concept describes how long an object exists?
9. File-scope static variables generally have:
10. Does an extern declaration necessarily define a new object?
PRACTICE

22.62 ๐ŸŽฏ Practice Problems

Practice auto, register, static locals, file-scope static names, extern, scope, lifetime, linkage, and multi-file design concepts. Use ๐Ÿ’ป Solve It Yourself first, open Hint only when needed, and use Show Program after attempting the problem.

๐Ÿ“ˆ Storage Classes Practice Progress
Solved 0 / 20
Completed with Solution 0
Total Score 0 / 400
Completion 0%
A problem counts as Solved when all test cases pass without opening the full solution. Problems completed after viewing the official solution are tracked separately.
1. Purpose of auto

Problem 1: Explain the purpose of the auto storage class using a runnable program.

Input: No input.

Output: Print a concise explanation.

2. Automatic Local Variable

Problem 2: Write a program using an automatic local variable.

Input: One integer.

Output: Print the local value after adding 10.

3. Purpose of register

Problem 3: Explain the purpose of register using a runnable program.

Input: No input.

Output: Print a concise explanation.

4. register Loop Counter

Problem 4: Write a program containing a register loop counter and calculate the sum from 1 to n.

Input: One positive integer n.

Output: Print the sum from 1 through n.

5. Why register is Not Guaranteed

Problem 5: Explain why register does not guarantee CPU-register allocation.

Input: No input.

Output: Print the explanation.

6. Static Local Variable

Problem 6: Write a function using a static local variable and call it three times.

Input: No input.

Output: Print 1 2 3.

7. Count Function Calls with static

Problem 7: Count how many times a function is called using a static local variable.

Input: One integer n indicating the number of calls.

Output: Print the final call count.

8. Automatic Local vs Static Local

Problem 8: Demonstrate the difference between an automatic local variable and a static local variable across two function calls.

Input: No input.

Output: Print auto and static values for two calls.

9. File-Scope static Variable

Problem 9: Create a file-scope static variable and use it from a function in the same source file.

Input: One integer.

Output: Print the static file-scope variable after adding the input.

10. Internal Linkage

Problem 10: Explain internal linkage with a file-scope static name.

Input: No input.

Output: Print the explanation.

11. Purpose of extern

Problem 11: Explain the purpose of extern with a runnable declaration and definition in one translation unit.

Input: No input.

Output: Print the shared value.

12. Share a Global Variable with extern

Problem 12: Model two C files that share a global variable using extern. The runnable solution combines the declarations into one translation unit while preserving the declaration/definition relationship.

Input: One integer to add to the shared value.

Output: Print the updated shared value.

13. Scope vs Lifetime

Problem 13: Explain the difference between scope and lifetime.

Input: No input.

Output: Print two concise lines.

14. Predict a Static Counter

Problem 14: Predict the output of a program containing a static counter function, then verify it.

Input: No input.

Output: Print 2 4 6 from three calls that add 2 each time.

15. Automatic or Static Storage Duration

Problem 15: Identify whether representative objects have automatic or static storage duration.

Input: No input.

Output: Print classifications for local, static local and file-scope global objects.

16. Why Uninitialized automatic Values are Unsafe

Problem 16: Explain why reading an uninitialized automatic variable is unsafe. Do not execute an indeterminate read.

Input: No input.

Output: Print the explanation.

17. static Global vs static Local

Problem 17: Explain the difference between static global and static local declarations.

Input: No input.

Output: Print scope/linkage/storage-duration differences.

18. Header extern Declaration

Problem 18: Model a header file containing an extern declaration and use it from another C file. The runnable version keeps the pieces together.

Input: No input.

Output: Print the shared configuration value.

19. static Helper Function

Problem 19: Create a static helper function that has internal linkage and use it inside the same source file.

Input: One integer.

Output: Print the square of the integer.

20. Mini Project with auto, register, static and extern

Problem 20: Create a small runnable program demonstrating auto, register, static and extern. A real multi-file project would place the extern declaration and definition in separate files.

Input: One positive integer n.

Output: Print the sum 1..n, the static call count, and the shared extern-backed global value.

22.63 Interview Questions

1. What is a storage class?
2. What is the difference between scope and lifetime?
3. Why is static local useful?
4. What is internal linkage?
5. What is external linkage?
6. Does register guarantee register storage?
7. What is the purpose of extern?
8. What is the difference between a declaration and a definition?
9. What happens to a static local variable after a function returns?
10. Why might static be used for a helper function?

22.64 Key Takeaway

๐ŸŽฏ Remember:

auto โ†’ ordinary local variable.

register โ†’ optimization request.

static local โ†’ remembers its value.

static file-scope โ†’ private to the translation unit.

extern โ†’ refers to an entity with linkage defined elsewhere.

Scope tells you WHERE a name can be used.

Lifetime tells you HOW LONG the object exists.

Linkage tells you whether declarations can refer to the same entity.
PLACEMENT TIPS

๐Ÿ’ก Storage Classes โ€” Placement Tips

  • Separate the ideas of scope, storage duration, and linkage; interview questions often test the difference.
  • A static local variable has block scope but static storage duration, so it preserves state between calls.
  • A file-scope static name has internal linkage and is commonly used to keep implementation details private to one source file.
  • An extern declaration does not automatically create a second object; normally one translation unit contains the definition.
  • Do not depend on register for optimization. Modern compilers decide register allocation themselves.
  • Never read an uninitialized automatic object. Static-duration objects, by contrast, receive zero initialization when no explicit initializer is supplied.
EXTRA PRACTICE

โœ๏ธ Storage Classes โ€” Extra Practice Questions

  1. Create two counters: one automatic local and one static local, and compare their values across five calls.
  2. Design a module with a file-scope static variable and public getter/setter functions.
  3. Create a two-file example where one file defines a global object and another accesses it through extern.
  4. Compare a file-scope static helper function with a non-static helper function in terms of linkage.
  5. Classify ten declarations by scope, storage duration, and linkage.
  6. Create a small configuration module with a header declaration, one global definition, and internal static helper data.
โ† Previous Topic: Operator Precedence & Associativity Next Topic: Advanced Preprocessor โ†’