2. Control Flow, Storage Classes & Scope
Scope vs Visibility vs Lifetime, storage classes (auto, register, static, extern), internal vs external linkage, switch fallthrough mechanics, and loop control traps in C
GATE CS & UGC NET JRF Core Subject Exam Weightage: 2–3 Direct Questions on static local variables inside nested loops/functions, switch fall-through quirks, and linkage differences between
staticandextern.
1. Technical Jargon & Core Concepts#
Variable management in C is dictated by three orthogonal properties:
+—————————————————————————————————————————————————————————————————————————+
| Scope: WHERE in the code the variable identifier is recognized. |
| Visibility:WHERE the identifier is accessible without being shadowed. |
| Lifetime: HOW LONG the allocated memory remains valid in execution. |
| Linkage: WHETHER the same identifier refers to the same object across |
| different translation units (.c files). |
+—————————————————————————————————————————————————————————————————————————+
- Scope Levels:
- Block Scope: Declared inside a block (
{ ... }). Visible from declaration to closing brace. - File Scope: Declared outside all blocks. Visible from declaration point to end of the translation unit.
- Function Scope: Applies exclusively to labels for
goto. Labels are visible everywhere inside their enclosing function. - Function Prototype Scope: Parameter names in forward declarations; discarded immediately after the prototype ends.
- Block Scope: Declared inside a block (
- Linkage Types:
- External Linkage: Identifier can be referenced across multiple translation units (global variables without
static, regular functions,extern). - Internal Linkage: Identifier can be accessed only within the translation unit where it is defined (file-scope
staticvariables and functions). - No Linkage: Local variables, formal parameters, and
typedefaliases; each declaration denotes a unique entity.
- External Linkage: Identifier can be referenced across multiple translation units (global variables without
- Storage Duration (Lifetime):
- Automatic: Allocated when the block is entered; deallocated when the block is exited. Stored on the runtime Call Stack.
- Static: Allocated at program startup in the data segment; persists throughout the entire program execution until process termination.
- Allocated: Dynamically allocated and freed via heap allocators (
malloc/free). - Thread: Introduced in C11 (
_Thread_local); persists for the duration of a thread.
2. Storage Classes in C#
C defines four primary storage class specifiers: auto, register, static, and extern.
| Storage Class | Storage Region | Default Value | Lifetime | Scope | Linkage |
|---|---|---|---|---|---|
| auto | Stack | Garbage (indeterminate) | Block execution | Block | None |
| register | CPU Register (or Stack) | Garbage (indeterminate) | Block execution | Block | None |
| static (local) | Data Segment (.data / .bss) | Zero (0) | Entire program | Block | None |
| static (global) | Data Segment (.data / .bss) | Zero (0) | Entire program | File | Internal |
| extern | Data Segment (.data / .bss) | Zero (0) | Entire program | Global | External |
2.1 The register Storage Class & Address-of Restriction#
The register keyword advises the compiler that the variable will be heavily accessed, requesting placement in a CPU register for speed.
[!CRITICAL] GATE Exam Trap: Address-of Operator
&on Register Variables! Because CPU registers do not have memory addresses in RAM, taking the address of aregistervariable using the address-of operator (&) is a COMPILE-TIME ERROR, even if the compiler placed it in RAM!Cregister int x = 10; int *p = &x; // COMPILE ERROR: address of register variable 'x' requested
2.2 The Dual Nature of static#
The keyword static has two entirely different meanings depending on where it appears:
Dual Meanings of 'static'
│
┌───────────────────────┴───────────────────────┐
▼ ▼
Local Variable Scope File Scope (Global)
Persists across function calls Restricts linkage to Internal
Initialized exactly ONCE at compile-time Hides variable/function from other
Preserves previous mutated state translation units (Encapsulation)
Tricky GATE Question: Local Static in Recursive Functions#
#include <stdio.h>
int f(int n) {
static int x = 0; // Initialized ONCE before program starts
if (n <= 0) return 1;
x++;
return f(n - 1) + x;
}
int main(void) {
printf("%d\n", f(3)); // What is the output?
return 0;
}
Step-by-step Trace:
f(3):xbecomes 1. Callsf(2) + x.f(2):xbecomes 2. Callsf(1) + x.f(1):xbecomes 3. Callsf(0) + x.f(0): Base case returns 1.- Notice: When returning and unwinding the call stack, what is the value of
x? Sincexis static and shared, its value is 3 across all stack frames!f(1)returns .f(2)returns .f(3)returns . Output: 10!
2.3 extern: Declaration vs. Definition#
// File: module.h
extern int counter; // DECLARATION: informs compiler 'counter' exists elsewhere. No memory allocated!
// File: module.c
int counter = 0; // DEFINITION: allocates memory in .bss/.data segment.
Tentative Definitions in C:
If a file-scope declaration has no storage class specifier or has static, and has no initializer, it is a tentative definition.
int x; // Tentative definition (valid C, initialized to 0 if no other definition exists)
int x; // Legal in C! Redundant tentative definition merged into one object.
3. Control Flow Mechanics & Traps#
3.1 The switch Statement & Fallthrough#
The switch statement evaluates an integral control expression and jumps directly to the matching case label.
#include <stdio.h>
int main(void) {
int x = 2;
switch (x) {
case 1: printf("1 ");
case 2: printf("2 "); // Matches here!
case 3: printf("3 "); // No break! Falls through!
default: printf("D ");// Falls through into default!
}
return 0;
}
// Output: 2 3 D
Key Syntax Constraints:#
- Integer Types Only:
switch(expr)requires an integral type (int,char,short,long,enum). Floating-point numbers (float,double) and strings are illegal. - Compile-Time Constant Case Expressions: Every
casevalue must be an integral constant expression (e.g.,case 3:orcase 'A':orcase 2 + 3:). Variables likecase x:are illegal. - Labels as Jump Targets:
caselabels are conceptually jump labels (similar togoto). This allows unusual but valid constructs like Duff's Device.
3.2 Duff's Device: Loop Unrolling via Switch#
In 1983, Tom Duff created a famous loop-unrolling mechanism that illustrates the true nature of switch in C:
// Copy 'count' elements from 'from' to 'to' unrolled by a factor of 8
void send(int *to, int *from, int count) {
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
3.3 Loop Evaluation Quirks: break vs. continue#
| Control Statement | Effect in for loop | Effect in while loop | Effect in switch |
|---|---|---|---|
| break | Terminates loop immediately, jumps past loop body | Terminates loop immediately, jumps past loop body | Exits switch block |
| continue | Skips remaining body, jumps to increment expression (step) | Skips remaining body, jumps directly to condition check | ILLEGAL unless enclosed within a loop |
// Classic Trap: Infinite loop caused by continue in while loop
int i = 0;
while (i < 5) {
if (i == 3) {
continue; // Jumps to 'while (i < 5)', SKIPPING 'i++'! Infinite loop!
}
printf("%d ", i);
i++;
}
4. Best Practices & Defensive Coding#
- Always Annotate Intentional Fallthrough:
In modern C, annotate intentional fallthrough using
/* fallthrough */comments or the C23 attribute[[fallthrough]]to silence compiler warnings. - Every
switchMust Have adefaultClause: Even if all expected cases are covered, adefault: assert(0);protects against future enum expansions or corrupted state. - Limit Variable Scope (Declare at Point of Use): Minimize the visibility lifetime of variables to reduce bug surface.
- Use
staticon Global Helper Functions: Mark all functions that are private to a file asstaticto prevent global namespace pollution and allow link-time optimization (inlining).
Practice Quiz
Test your understanding with step-by-step solutions
Practice Quiz
10 questions · 90s per question
Each question has a 90-second time limit. Unanswered questions will be auto-submitted when time runs out.