The Lifecycle of Data
Every variable in C has two properties that define its behavior:
- Scope: The region of code where the variable is visible.
- Storage Duration: How long the variable stays in memory.
Storage Classes
1. auto
The default for local variables. They are stored on the Stack and have Automatic Storage Duration (destroyed when the block ends).
2. static
The static keyword has two distinct meanings depending on where it is used:
- Inside a Function: The variable’s lifetime is extended to the entire program duration (stored in the Data/BSS segment). It retains its value between function calls.
- At File Scope: The variable has Internal Linkage, meaning it is only visible within that specific
.cfile and cannot be accessed by other files viaextern.
3. extern
Used to declare a variable or function that is defined in another Translation Unit (file). It gives the variable External Linkage.
// file1.c
int global_count = 10;
// file2.c
extern int global_count; // Accesses the variable in file1.c
4. register
A hint to the compiler to store the variable in a CPU Register instead of RAM for faster access. Modern compilers are so good at register allocation that this is rarely used today, except in extremely tight loops.
Type Qualifiers
const
Indicates that the variable’s value cannot be changed after initialization. This allows the compiler to perform optimizations and move data to read-only memory.
volatile: The Embedded Essential
The volatile qualifier tells the compiler: “This variable can change at any time without this code doing anything.”
- Example: A memory-mapped hardware register or a shared variable in a multi-threaded application.
- Without
volatile, the compiler might optimize away “redundant” reads, failing to see the hardware change.
volatile int *sensor = (int*)0x40001234;
while (*sensor == 0) { /* Wait for hardware event */ }
// Without volatile, the compiler might turn this into an infinite loop!
Pointer Qualifiers
Qualifiers can be applied to the pointer itself or the data it points to. This distinction is vital for API design:
| Declaration | Meaning |
|---|---|
const int *p | Pointer to a constant integer (Data cannot change). |
int * const p | Constant pointer to an integer (Address cannot change). |
const int * const p | Constant pointer to a constant integer (Nothing can change). |
Static Lifetime
int get_next_id() { int id = 0; return ++id; }
Interactive Lab
Waiting for signal...