Skip to main content

C Callback Functions Explained: Function Pointers in Practice

·549 words·3 mins
C Programming Callbacks Function Pointers Embedded Systems
Table of Contents

Callback functions are a cornerstone of modular, flexible, and decoupled C programs. To fully understand callbacks, you must first master the true “soul” of C: pointers, and more specifically, function pointers.

Callbacks are widely used in operating systems, embedded firmware, libraries, and event-driven architectures where behavior must be customized without modifying core logic.


🧠 Function Pointers
#

While pointers are commonly used to reference data, function pointers reference executable code stored in memory.

Definition
#

The general syntax for declaring a function pointer is:

ReturnType (*PointerName)(ParameterList);

The parentheses around (*PointerName) are mandatory. Without them, the declaration would instead describe a function returning a pointer.

Improving Readability with typedef
#

Function pointer syntax can be hard to read. typedef is commonly used to simplify declarations:

typedef int (*CalcFunc)(int, int);

This defines CalcFunc as a type representing any function that takes two int parameters and returns an int.

Calling a Function via a Pointer
#

int Max(int x, int y) {
    return x > y ? x : y;
}

int main(void) {
    int (*p)(int, int) = Max;   // or &Max
    int result = p(10, 20);     // or (*p)(10, 20)
    return 0;
}

Once assigned, a function pointer can be invoked just like a normal function.


🔁 What Is a Callback Function?
#

A callback function is a function that is invoked indirectly through a function pointer.

In simple terms:

  • Function A is passed as an argument to function B
  • Function B later calls function A
  • Function A is the callback

Core Roles
#

  • Library / Framework Code: Provides generic behavior
  • Callback Function: Supplies application-specific logic

The caller does not need to know which function it is calling—only that the function matches the expected prototype.

Why Callbacks Matter
#

Callbacks enable loose coupling and extensibility, and are heavily used in:

  1. Event handling (e.g., GUI or interrupt-driven systems)
  2. Algorithms (e.g., sorting and searching)
  3. State machines (e.g., hardware or protocol control)
  4. Operating systems and drivers

A classic example is qsort(), where the comparison logic is supplied by the user as a callback.


🛠 Practical Callback Examples
#

Example A: Dynamic Math Operations
#

A single handler can perform different operations by receiving different callback functions:

float add_sub_mul_div(float a, float b, float (*op_func)(float, float)) {
    return op_func(a, b);   // Callback invocation
}

// Usage
printf("Result: %f\n", add_sub_mul_div(10, 5, ADD));
printf("Result: %f\n", add_sub_mul_div(10, 5, SUB));

The handler remains unchanged while behavior varies dynamically.


Example B: Embedded State Machine (Professional Pattern)
#

In embedded systems, callbacks are commonly used to implement state machines cleanly and safely.

typedef struct {
    uint8_t mStatus;
    uint8_t (*Function)(void);
} WorkStatus_TypeDef;

WorkStatus_TypeDef Status_Tab[] = {
    { OPEN_NETWORK, M26_PWRKEY_On },
    { INIT_PINS,    M26_Work_Init },
    { CONFIG_AT,    M26_NET_Config }
};

uint8_t Execute_State(uint8_t current_state) {
    for (int i = 0; i < 3; i++) {
        if (current_state == Status_Tab[i].mStatus) {
            return Status_Tab[i].Function(); // Callback execution
        }
    }
    return 0;
}

This pattern offers:

  • Clear state-to-handler mapping
  • Easy extensibility
  • Strong separation of logic

It is widely used in firmware for modems, sensors, and real-time control systems.


🧾 Summary
#

  • Function pointers store addresses of executable code
  • Callbacks allow code to invoke user-defined behavior indirectly
  • They enable modular design, runtime flexibility, and clean abstractions
  • Callbacks are fundamental in embedded systems, libraries, kernels, and event-driven software

Mastering callback functions is a key step toward writing professional-grade C code.

Related

Advanced Application Scenarios of Function Pointers in C
·784 words·4 mins
C Programming Function Pointers Embedded Systems Software Design
High-Quality C Programming: Practical Techniques for Robust Systems Code
·700 words·4 mins
C Programming Embedded Systems RTOS Low-Level Programming
Linux SPI Driver Explained: Architecture and Driver Design
·684 words·4 mins
Linux SPI Device Driver Embedded Systems