Mastering C Function Pointers: From Basics to Advanced Embedded Applications
This article explains what function pointers are in C, shows their declaration syntax, provides simple and advanced usage examples—including callbacks, state machines, and command dispatch—offers best‑practice tips, and demonstrates how they empower flexible embedded development.
What is a Function Pointer
In C a pointer stores a memory address. A function pointer is a variable that stores the entry address of a function, allowing indirect calls.
Declaration syntax
General form: return_type (*pointer_name)(parameter_type_list); Examples:
int (*func_ptr)(int, int); // points to a function returning int
void (*callback)(float); // points to a function returning void
char *(*get_string)(void); // points to a function returning char *Parentheses around (*pointer_name) are mandatory; omitting them changes the declaration.
Basic Usage
Simple example
#include <stdio.h>
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int main(void) {
int (*operation)(int, int); // declare function pointer
operation = add; // or operation = &add;
int r1 = operation(10, 5);
printf("10 + 5 = %d
", r1);
operation = subtract;
int r2 = operation(10, 5);
printf("10 - 5 = %d
", r2);
return 0;
}The two assignment forms and the two call forms are equivalent.
Simplifying with typedef
typedef int (*MathOperation)(int, int);
MathOperation op1 = add;
MathOperation op2 = subtract;
MathOperation ops[2] = { add, subtract };Typical Embedded Applications
Callback mechanism
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
/* HAL internally stores the address of the user‑provided callback in a function‑pointer member and invokes it when the timer expires. */State‑machine implementation
typedef void (*StateHandler)(void);
void state_idle(void) { printf("System in IDLE state
"); }
void state_running(void){ printf("System in RUNNING state
"); }
void state_error(void) { printf("System in ERROR state
"); }
typedef struct { StateHandler current_state; } StateMachine;
StateMachine sm;
void state_machine_init(void) { sm.current_state = state_idle; }
void state_machine_run(void) { if (sm.current_state) sm.current_state(); }
void change_state(StateHandler new_state) { sm.current_state = new_state; }Command dispatch system
typedef void (*CommandHandler)(uint8_t *data, uint16_t len);
void cmd_read_sensor(uint8_t *data, uint16_t len) { printf("Reading sensor data...
"); }
void cmd_write_config(uint8_t *data, uint16_t len){ printf("Writing configuration...
"); }
void cmd_reset_system(uint8_t *data, uint16_t len){ printf("Resetting system...
"); }
typedef struct {
uint8_t cmd_id;
CommandHandler handler;
} CommandEntry;
CommandEntry command_table[] = {
{0x01, cmd_read_sensor},
{0x02, cmd_write_config},
{0x03, cmd_reset_system}
};
void dispatch_command(uint8_t cmd_id, uint8_t *data, uint16_t len) {
for (size_t i = 0; i < sizeof(command_table)/sizeof(CommandEntry); ++i) {
if (command_table[i].cmd_id == cmd_id && command_table[i].handler) {
command_table[i].handler(data, len);
return;
}
}
printf("Unknown command: 0x%02X
", cmd_id);
}Advanced Techniques
Array of function pointers
typedef void (*MenuFunction)(void);
void menu_item1(void) { printf("Executing menu item 1
"); }
void menu_item2(void) { printf("Executing menu item 2
"); }
void menu_item3(void) { printf("Executing menu item 3
"); }
MenuFunction menu_functions[] = { menu_item1, menu_item2, menu_item3 };
void execute_menu(int choice) {
size_t menu_size = sizeof(menu_functions)/sizeof(MenuFunction);
if (choice >= 0 && (size_t)choice < menu_size) {
menu_functions[choice]();
} else {
printf("Invalid menu choice
");
}
}Function returning a function pointer
typedef int (*Operation)(int, int);
Operation get_operation(char op) {
switch (op) {
case '+': return add;
case '-': return subtract;
default: return NULL;
}
}
/* Example usage */
Operation op = get_operation('+');
if (op) {
int result = op(10, 5);
printf("Result: %d
", result);
}Function pointers as struct members (object‑oriented style)
typedef struct {
int id;
char name[32];
void (*init)(void);
void (*process)(uint8_t *data);
void (*deinit)(void);
} Device;
void sensor_init(void) { printf("Sensor initialized
"); }
void sensor_process(uint8_t *data) { printf("Processing sensor data
"); }
void sensor_deinit(void) { printf("Sensor deinitialized
"); }
Device sensor = {
.id = 1,
.name = "Temperature Sensor",
.init = sensor_init,
.process = sensor_process,
.deinit = sensor_deinit
};
/* Invocation */
sensor.init();
sensor.process(NULL);
sensor.deinit();Best Practices and Pitfalls
Type safety
The signature of a function pointer must match the target function exactly. Mismatched signatures lead to undefined behavior.
/* Wrong: parameter types differ */
float (*wrong_ptr)(float, float) = add; // dangerous!
/* Correct */
int (*correct_ptr)(int, int) = add;Null‑pointer checks
void (*callback)(void) = NULL;
/* Bad: calling without check */
// callback();
/* Good */
if (callback) callback();Initialization
Always initialize a function pointer to a valid function or NULL to avoid wild pointers.
void (*handler)(void) = NULL; // safe default
/* or */
void default_handler(void) { /* ... */ }
void (*handler)(void) = default_handler;Conclusion
Function pointers provide dynamic dispatch, callback support, and modular design in embedded C. Mastering their declaration, usage patterns (callbacks, state machines, command tables, struct‑based interfaces) and safety rules is essential for robust low‑level software.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
