Keywords in C
Contents
Introduction
Keywords like `static`, `const`, and `volatile` modify variable behavior in C. This document explains their use cases, advantages, disadvantages, and interactions.
1. The `static` Keyword
Definition:
`static` controls the scope and lifetime of variables/functions.
Types of Declarations:
1. Static Local Variables:
- Retain value between function calls.
- Stored in the data segment (not stack).
- Scope: Local to the block.
- Lifetime: Entire program execution.
Example:
#include <stdio.h>
void counter() {
static int count = 0; // Preserved across calls
count++;
printf("Count: %d\n", count);
}
int main() {
counter(); // Count: 1
counter(); // Count: 2
return 0;
}
2. Static Global Variables/Functions:
- Scope limited to the file where declared.
- Avoids naming conflicts in multi-file projects.
Example:
// File: utils.c
static int hidden = 10; // Only visible in this file
static void print_hidden() { // File-local function
printf("%d\n", hidden);
}
Use Cases:
- Preserve state between function calls (e.g., counters).
- Encapsulate variables/functions within a file.
Advantages:
- Prevents unintended external access.
- Reduces namespace pollution.
Disadvantages:
- Overuse increases memory usage (data segment).
2. The `const` Keyword
Definition:
`const` declares read-only variables. Attempts to modify them cause compiler errors.
Types of Declarations:
1. Constant Variables:
const int MAX = 100;
MAX = 200; // Error: Assignment to read-only variable
2. Pointers to Constants:
const int *ptr = &MAX;
*ptr = 200; // Error: Can't modify via ptr
3. Constant Pointers:
int x = 5;
int *const ptr = &x; // Pointer address is fixed
ptr = &y; // Error: Can't reassign ptr
Use Cases:
- Define configuration values (e.g., buffer sizes).
- Enforce immutability in function parameters.
Advantages:
- Prevents accidental modification.
- Improves code readability.
Disadvantages:
- Can’t be used for runtime-initialized constants (requires `#define` or `enum`).
3. The `volatile` Keyword
Definition:
`volatile` tells the compiler that a variable’s value may change unexpectedly (e.g., hardware registers, ISRs).
Example (Without `volatile` Optimization):
int flag = 0;
while (flag == 0) {
// Compiler may optimize this loop into "while(true)"
}
Example (With `volatile`):
volatile int flag = 0;
while (flag == 0) {
// Compiler checks flag on every iteration
}
Use Cases:
- Memory-mapped hardware registers.
- Variables modified in interrupts or multithreaded code.
Advantages:
- Ensures fresh reads from memory.
- Disables dangerous compiler optimizations.
Disadvantages:
- Reduces optimization opportunities.
4. Combined Keywords
1. `const + volatile`
Use Case:
- A read-only hardware register (e.g., status register).
- Value can change externally, but code shouldn’t write to it.
Example:
const volatile uint32_t *STATUS_REG = (uint32_t*)0x4000;
// Can’t modify STATUS_REG, but its value may change
uint32_t status = *STATUS_REG; // Read-only access
2. `static + volatile`
Use Case:
- A variable shared between an ISR and a function, but scoped to a file.
Example:
static volatile bool data_ready = false;
void ISR() {
data_ready = true; // Modified in ISR
}
void process_data() {
while (!data_ready); // Wait in main code
// Process data
}
3. `static + const`
Use Case:
- A file-local constant (e.g., lookup table).
Example:
static const float PI = 3.14159; // File-scoped constant
Comparison Table
Combination | Use Case | Example |
---|---|---|
`static` | Preserve state across calls | Counters, file-local vars |
`const` | Immutable data | Configuration constants |
`volatile` | Externally-modified variables | Hardware registers |
`const + volatile` | Read-only hardware registers | Status registers |
`static + volatile` | Shared ISR-main thread variables | Sensor flags |
Key Takeaways
- `static`: Control scope/lifetime.
- `const`: Enforce immutability.
- `volatile`: Disable optimizations for unstable variables.
- Combine keywords for specialized use cases (e.g., `const volatile`).
Common Pitfalls
- Forgetting `volatile` for variables modified in ISRs.
- Using `const` with pointers incorrectly (e.g., `const int*` vs `int* const`).
- Overusing `static` leading to higher memory usage.