Volatile keyword and why it matters in Embedded C - Time & Space Complexity
When using the volatile keyword, it affects how the program reads and writes variables that can change unexpectedly.
We want to understand how this impacts the number of operations the program performs as input changes.
Analyze the time complexity of the following code snippet.
volatile int flag = 0;
void wait_for_flag() {
while(flag == 0) {
// wait here
}
// flag changed, continue
}
This code waits in a loop until the flag variable changes, which might happen outside this code.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The
whileloop repeatedly checks theflagvariable. - How many times: It runs until
flagchanges from 0 to non-zero.
The loop runs as many times as it takes for flag to change. If the change is delayed, the loop runs longer.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks of flag |
| 100 | About 100 checks of flag |
| 1000 | About 1000 checks of flag |
Pattern observation: The number of checks grows directly with how long the program waits for flag to change.
Time Complexity: O(n)
This means the time spent waiting grows linearly with how many times the loop checks the variable before it changes.
[X] Wrong: "The compiler will always check the variable fresh, so volatile is not needed."
[OK] Correct: Without volatile, the compiler might optimize by reading the variable once and reusing it, causing the loop to never see changes made outside.
Understanding how volatile affects loops and variable access shows you know how hardware and compilers interact, a key skill in embedded programming.
"What if we removed the volatile keyword? How would the time complexity and program behavior change?"
Practice
volatile keyword tell the compiler about a variable?Solution
Step 1: Understand the role of
Thevolatilevolatilekeyword tells the compiler that the variable's value can change unexpectedly, such as by hardware or interrupts.Step 2: Identify what this means for the compiler
The compiler must not optimize away reads or writes to this variable because its value can change outside normal program flow.Final Answer:
The variable can change at any time outside the program flow -> Option DQuick Check:
volatilemeans variable changes anytime [OK]
- Thinking volatile means variable is constant
- Assuming volatile stores variable in register
- Confusing volatile with static or const
flag?Solution
Step 1: Recall volatile declaration syntax
In C,volatilecan appear before or after the type specifier, so bothvolatile int flag;andint volatile flag;are valid.Step 2: Check each option
int volatile flag; and volatile int flag; are both correct syntax. int flag volatile; is invalid becausevolatilemust come before or immediately after the type, not after the variable name.Final Answer:
Both A and B are correct -> Option CQuick Check:
Volatile can be before or after type [OK]
- Placing volatile after variable name
- Using volatile without type
- Confusing volatile with const syntax
volatile int flag = 0;
void loop() {
while(flag == 0) {
// wait
}
// do something
}What happens if
flag is not declared volatile and is changed by an interrupt?Solution
Step 1: Understand compiler optimization without volatile
Ifflagis not volatile, the compiler may assume it does not change inside the loop and optimize by reading it once.Step 2: Effect on loop behavior
Because the compiler caches the value, changes made by interrupts toflagmay be ignored, causing the loop to never end.Final Answer:
The loop may never end because compiler optimizes flag check -> Option AQuick Check:
Without volatile, compiler may cache variable [OK]
- Thinking code will always work without volatile
- Assuming volatile causes compilation errors
- Believing volatile slows down program always
int data_ready = 0;
void ISR() {
data_ready = 1;
}
void main_loop() {
while(data_ready == 0) {
// wait
}
// process data
}How to fix it?
Solution
Step 1: Identify variable shared with ISR
data_readyis changed inside an interrupt service routine (ISR) and read in main loop.Step 2: Understand why volatile is needed
Withoutvolatile, compiler may optimize and cachedata_ready, ignoring changes from ISR.Step 3: Fix by declaring volatile
Declaringvolatile int data_ready = 0;tells compiler to always read fresh value.Final Answer:
Declaredata_readyasvolatile int data_ready = 0;-> Option AQuick Check:
Shared ISR variables must be volatile [OK]
- Using static instead of volatile
- Removing loop without fixing variable
- Making variable constant incorrectly
0x4000 that changes asynchronously. Which declaration ensures safe access to this register in embedded C?Solution
Step 1: Understand hardware register behavior
Hardware registers can change anytime outside program control, so compiler must not optimize access.Step 2: Choose correct pointer declaration
Declaring pointer asvolatile int *tells compiler to always read/write actual memory, not cached value.Step 3: Evaluate options
int *reg = (int *)0x4000; lacks volatile, risking optimization. const int *reg = (int *)0x4000; makes it constant, disallowing writes. static int *reg = (int *)0x4000; uses static incorrectly.Final Answer:
volatile int *reg = (int *)0x4000; -> Option BQuick Check:
Hardware registers need volatile pointers [OK]
- Omitting volatile causing stale reads
- Using const preventing writes
- Confusing static with volatile
Ready to prove it?
Pass the test and this pattern moves unknown
