- References
- Function Overloading
- Default Function Arguments
- Inline Function
- Dynamic Memory Allocation
- Placement New
- nullptr
- Namespaces
- Type Aliases
- Enum classes
- constexpr
- static_assert
- mutable Keyword
- auto Keyword
- Smart Pointers
- Basics of Classes
- Constructors
- Destructors
- Operator Overloading
- Copy Semantics
- Move Semantics
- Composition, RAII & Ownership
- Inheritance
- Polymorphism
- Abstraction
- Encapsulation
- Template
- Static Memory
- Friend Function
- this Pointer
- Function Pointer
- Lambdas and Callback Management
- Union
Function Pointers (Dynamic Execution)

Variables usually hold Data (integers, floats).
A Function Pointer is a variable that holds Code (the address of a function in Flash memory).
It allows you to decide which function to run at runtime, rather than compile time.
Think of it as a "Blank Button" on a remote control. You can program this button to do "Volume Up" today, and reprogram it to do "Change Channel" tomorrow. The hardware (the button) stays the same; the behavior changes.
Syntax & Usage (The "C" Style)
The syntax is notoriously ugly ("Right-Left Rule"), but essential to know.
Declaration:
Return_Type (*Pointer_Name)(Argument_Types);
// 1. Define standard functions
void led_on() { printf("LED ON\n"); }
void led_off() { printf("LED OFF\n"); }
int main() {
// 2. Declare a function pointer named 'action'
// It can point to ANY function that takes void and returns void.
void (*action)();
// 3. Assign address (Function name is the address)
action = &led_on;
action(); // Calls led_on() -> Prints "LED ON"
// 4. Re-assign dynamically
action = &led_off;
action(); // Calls led_off() -> Prints "LED OFF"
}Modern C++ Alternative (using):
To make it readable, use using (or typedef).
using EventHandler = void (*)(int); // 'EventHandler' is now a type
EventHandler myPtr = &someFunction;Key Patterns in Firmware
A. Callbacks (Event Notification)
Instead of hardcoding what happens when a button is pressed, the driver lets the user "register" a function.
// --- Driver File ---
// Variable to store the user's function
void (*button_callback)(void) = nullptr;
void register_callback( void (*cb)(void) ) {
button_callback = cb;
}
// ISR (Interrupt)
void Button_ISR() {
// If a user registered a function, call it!
if (button_callback != nullptr) {
button_callback();
}
}
// --- Application File ---
void my_app_logic() { printf("Button Pressed!"); }
int main() {
register_callback(&my_app_logic); // Hook it up
}B. Jump Tables (State Machines)
Instead of a giant switch-case with 50 if/else blocks, use an array of function pointers. This is O(1) (Constant Time) and extremely fast.
// Define the state handler type
using StateHandler = void (*)();
void handle_idle() { /* ... */ }
void handle_run() { /* ... */ }
void handle_error() { /* ... */ }
// The Jump Table (Array of functions)
StateHandler state_machine[] = {
&handle_idle, // Index 0
&handle_run, // Index 1
&handle_error // Index 2
};
// Run state 'current_state' (No if/else needed!)
state_machine[current_state](); Advanced: Member Function Pointers (The Trap)
This is the most common error for C++ beginners.
A regular function pointer cannot point to a non-static class member function.
Reason: Member functions have a hidden
thisargument. Regular pointers don't know how to handlethis.Syntax: You must include the class name scope.
class Motor {
public:
void stop() { /* ... */ }
};
int main() {
// void (*ptr)() = &Motor::stop; // ❌ ERROR: Type Mismatch
// Correct Syntax (Member Function Pointer)
void (Motor::*ptr)() = &Motor::stop;
Motor m;
(m.*ptr)(); // Syntax to call it on object 'm' (Very rare in practice)
}Fix: In Embedded C++, if you need a callback to a class method, either use a Static member function (which matches regular pointers) or pass a
void* context(thethispointer) alongside the function pointer.
Relevance in Embedded/Firmware
1. Bootloaders (Jump to App)
A bootloader runs, checks for a new firmware, and then jumps to the main application.
It does this by casting a specific memory address (e.g., 0x08004000) to a function pointer and calling it.
// "Function" at specific address
void (*app_reset_handler)(void) = (void (*)(void)) (*(uint32_t*)0x08004004);
// Jump!
app_reset_handler(); 2. Interrupt Vector Table (IVT)
The IVT is literally just an array of function pointers stored at the beginning of Flash. When an interrupt fires, the hardware looks up the address in this array and jumps to it.
Common Pitfalls (Practical Tips)
Pitfall | Details |
|---|---|
❌ Dereferencing Null | Always check if (ptr != nullptr) before calling. Calling a null function pointer causes a Hard Fault (Crash) instantly because the CPU tries to execute code at address 0x00. |
❌ Signature Mismatch | The pointer type must matches the function exactly. If the pointer expects void (*)(int) and you point it to void (*)(float), the arguments will be passed via wrong CPU registers, leading to garbage data. |
❌ C++ Casts | Do not use reinterpret_cast to force a Class::Method into a void (*)() pointer. It might compile, but it will crash at runtime because the this pointer is missing. |
✅ Use | In full C++ (Linux/Windows), we use std::function. In small Embedded systems, we avoid it because it uses malloc (Heap) to store the closure. Stick to raw C-style pointers or simple template callbacks. |
Summary Checklist
Use
usingortypedefto make syntax readable.Always check for
NULLbefore calling.Use Jump Tables to replace massive switch-statements.
Remember: You cannot point a raw pointer to a non-static class member.
Concept understood? Let's apply and learn for real