What is the scope and lifetime of the static keyword in C language?
Three Uses of static Keyword:
-
Static Local Variables
cvoid counter() { static int count = 0; // Initialized only once count++; printf("Count: %d\n", count); } int main() { counter(); // Count: 1 counter(); // Count: 2 counter(); // Count: 3 } -
Static Global Variables
cstatic int global_var = 100; // File scope void function() { global_var++; } // Other files cannot access global_var -
Static Functions
cstatic void helper_function() { printf("This is a static function\n"); } // Can only be called within current file
Scope and Lifetime:
-
Static Local Variables
cvoid example() { // Scope: Within function // Lifetime: Entire program execution static int value = 10; // Retains previous value on each call value++; } -
Static Global Variables
c// file1.c static int file_global = 50; // file2.c extern int file_global; // Link error -
Static Functions
c// file1.c static int internal_calculation(int x) { return x * 2; } // file2.c int internal_calculation(int x); // Link error
Practical Application Scenarios:
-
Singleton Pattern
cint* get_instance() { static int *instance = NULL; if (instance == NULL) { instance = malloc(sizeof(int)); *instance = 0; } return instance; } -
Caching Mechanism
cint expensive_calculation(int n) { static int cache[100] = {0}; if (n < 100 && cache[n] != 0) { return cache[n]; } int result = /* complex calculation */; if (n < 100) { cache[n] = result; } return result; } -
Counter
cint get_unique_id() { static int next_id = 0; return next_id++; } -
State Maintenance
cvoid state_machine() { static enum { INIT, RUNNING, DONE } state = INIT; switch (state) { case INIT: printf("Initializing...\n"); state = RUNNING; break; case RUNNING: printf("Running...\n"); state = DONE; break; case DONE: printf("Done!\n"); break; } }
Difference from const:
- static vs const
c
// static: Controls scope and lifetime static int value = 10; // const: Controls modifiability const int value = 10; // Can be combined static const int CONSTANT = 100;
Thread Safety Considerations:
-
Non-Thread-Safe Static Variables
cint* get_instance_unsafe() { static int *instance = NULL; // Not thread-safe if (instance == NULL) { instance = malloc(sizeof(int)); } return instance; } -
Thread-Safe Static Variables
c#include <pthread.h> int* get_instance_safe() { static int *instance = NULL; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); if (instance == NULL) { instance = malloc(sizeof(int)); } pthread_mutex_unlock(&mutex); return instance; }
Best Practices:
-
Information Hiding
c// module.c static int internal_state = 0; static void internal_helper() { internal_state++; } void public_interface() { internal_helper(); } -
Avoid Global Variable Pollution
c// Use static to limit scope static int module_config = 0; void set_config(int value) { module_config = value; } -
Initialization Order
cvoid function() { static int initialized = 0; static int cache[100]; if (!initialized) { for (int i = 0; i < 100; i++) { cache[i] = i * i; } initialized = 1; } return cache[10]; }