The static keyword is one of the most overloaded words in C. It does three fundamentally different things depending on where you put it. Mixing up which meaning applies is a common source of bugs and linker errors.
Meaning 1: Static Local Variable — Persists Between Calls
#include <stdio.h>
int counter() {
static int count = 0; /* initialised once, persists between calls */
count++;
return count;
}
int main() {
printf("%dn", counter()); /* 1 */
printf("%dn", counter()); /* 2 */
printf("%dn", counter()); /* 3 */
return 0;
}
A static local variable is initialised once (at program start, or the first time the function runs — the standard guarantees this) and retains its value across all subsequent calls. It lives in the BSS or data segment, not on the stack.
This is the C way to remember state between function calls without using a global variable. It is also how you implement counters, caches, and lazy initialisation.
/* Lazy initialisation pattern */
const char *get_system_name() {
static char name[64] = {0};
static int loaded = 0;
if (!loaded) {
gethostname(name, sizeof(name));
loaded = 1;
}
return name;
}
Warning: static local variables are not thread-safe without synchronization. Two threads calling get_system_name concurrently can both see loaded == 0 and both try to initialise.
Meaning 2: Static Global Variable — File Scope Only
/* file: utils.c */
static int helper_count = 0; /* visible only within utils.c */
static void reset_count() { /* cannot be called from other files */
helper_count = 0;
}
void increment() {
helper_count++;
}
int get_count() {
return helper_count;
}
/* file: main.c */
extern int helper_count; /* LINKER ERROR — helper_count has internal linkage */
A static global variable or function has internal linkage: it is invisible to the linker and cannot be accessed from other translation units. This is the C equivalent of a private implementation detail.
Use static on every function and variable in a .c file that is not part of the public interface. It prevents name collisions, reduces binary size, and helps the compiler optimise more aggressively (it knows no external code calls the function).
Meaning 3: Static in Function Parameters — Array Hint
#include <stdio.h>
/* The static here is a hint: arr has at least 5 elements */
void print_first_five(int arr[static 5]) {
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("n");
}
int main() {
int data[] = {1, 2, 3, 4, 5, 6, 7};
print_first_five(data);
return 0;
}
In a function parameter, int arr[static N] tells the compiler the array argument has at least N elements and is never NULL. The compiler can use this to enable vectorization and eliminate null checks. It is a C99 feature and purely informational — no runtime check is performed.
Storage Duration Summary
| Declaration | Lifetime | Visibility |
|---|---|---|
| Local variable | Function call | Local only |
static local variable |
Program duration | Local only |
| Global variable | Program duration | All translation units |
static global variable |
Program duration | Current file only |
static function |
Program duration | Current file only |
The Pattern You Should Always Use
/* In a header file (public interface) */
void process_data(const char *data, size_t len);
int get_result(void);
/* In the .c file (implementation) */
static int result = 0; /* private state */
static void validate(const char *data); /* private helper */
void process_data(const char *data, size_t len) {
validate(data);
/* ... */
}
int get_result(void) {
return result;
}
static void validate(const char *data) {
/* only callable from within this .c file */
}
Think of static at file scope as the equivalent of private in OOP languages — it hides implementation details that callers should not depend on. If a function is only used within one file, mark it static. Understanding how pointers work in C alongside static state is key to writing encapsulated C modules.
Static Initialisation Order
#include <stdio.h>
static int x = 10; /* zero-initialised if omitted, BSS segment */
static int y = x * 2; /* ERROR: not a constant expression */
static int z = 20; /* OK — literal constant */
Static storage duration variables (both global and static local) must be initialised with constant expressions. You cannot initialise one static variable with the value of another (unlike C++). They are all initialised before main() runs.
TL;DR
staticinside a function: variable persists between calls, initialised oncestaticoutside a function: limits visibility to the current file (internal linkage)staticin a parameter array: tells the compiler the pointer is non-null with at least N elements- Mark every file-scoped function and variable
staticunless it is part of the public API - Static local variables are not thread-safe — use synchronization if multiple threads call the function
- Static variables in the BSS segment are zero-initialised automatically
- Test your static variable behaviour in our c program compiler — paste and run to see persistence between calls