본문 바로가기

C

C: function pointer

728x90
반응형

ESP-IDF의 예시코드

typedef void (*esp_hidd_event_cb_t) (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);

 

function pointer

  - 함수의 주소를 가리키는 포인터

  - callback, event driven 함수에서 유용하게 사용 가능

 

 

Function pointers in C are a powerful feature that allow you to store the address of a function in a variable, and use that variable to call the function. This can be very useful for implementing callbacks, passing functions as arguments to other functions, and managing event-driven programming. Here’s a detailed look at how function pointers work from the basics:

Basic Definition

A function pointer is just what it sounds like: a pointer that points to a function. Like any pointer, a function pointer holds an address, but instead of pointing to a data value (like an int or char), it points to the starting address of a block of executable code.

Syntax

The syntax for declaring a function pointer can be a bit confusing at first because of the placement of the asterisk. Here’s a general form:

return_type (*pointer_name)(parameter_list);
  • return_type is the type of value returned by the function.
  • pointer_name is the name of the function pointer.
  • parameter_list specifies the types of parameters that the function takes.

 

Example: Function Pointer Declaration

Let's say we have a simple function that adds two integers:

int add(int a, int b) {
    return a + b;
}

 

You can declare a function pointer that can point to this function as follows:

int (*add_ptr)(int, int);

 

Assigning a Function to a Pointer

To assign the function to the pointer, you simply use the function name without the parentheses:

add_ptr = add;

 

Using a Function Pointer

To call a function through its pointer, you use the pointer the same way you use the function name,

but with the pointer variable:

int result = add_ptr(3, 4);  // Calls add(3, 4) via the function pointer

 

 

Passing Function Pointers as Arguments

Function pointers are often used to pass a function as an argument to another function. For example, if you have a sort function, you can pass different comparison functions to it to sort data in different ways.

void sort(int* array, int n, int (*compare)(int, int)) {
    // implementation of sorting algorithm that uses compare for ordering elements
}

int ascending(int a, int b) {
    return a - b;
}

int descending(int a, int b) {
    return b - a;
}

// Usage:
sort(my_array, my_array_length, ascending);
sort(my_array, my_array_length, descending);

 

Benefits of Using Function Pointers

  1. Flexibility: Function pointers allow you to choose at runtime which function to call, rather than having to hard-code the function call.
  2. Customizability: They are crucial for writing generic reusable libraries. For example, the qsort function in the standard library uses function pointers to sort an array in any way the user desires.
  3. Event Handling: They are used extensively in systems programming (e.g., handling interrupts or callbacks).

Caution

While powerful, function pointers should be used judiciously as incorrect use can lead to complex and hard-to-debug code. Also, because they hold addresses to executable code, improper handling can lead to security vulnerabilities, especially in systems programming.

 

 

Event driven programming Example

  1. Define a few handler functions for different types of simulated events (e.g., error handling, user interaction).
  2. Create a dispatcher that calls the appropriate handler based on the event type.
  3. Use function pointers to allow different handlers to be registered and called dynamically.

Step-by-Step Code

Here's the full example broken down into parts:

1. Define Event Types and Handlers

#include <stdio.h>

// Define types of events
typedef enum {
    EVENT_LOGIN,
    EVENT_LOGOUT,
    EVENT_ERROR
} EventType;

// Function prototypes for event handlers
void handleLogin() {
    printf("Login event handled.\n");
}

void handleLogout() {
    printf("Logout event handled.\n");
}

void handleError() {
    printf("Error event handled.\n");
}

 

2. Event Dispatcher Function

This function uses a function pointer to call the appropriate event handler based on the event type.

void eventDispatcher(EventType type, void (*eventHandler)()) {
    // Call the appropriate event handler
    eventHandler();
}

 

3. Main Function to Simulate Events

The main function sets up function pointers to different handlers based on simulated incoming events.

int main() {
    // Simulate an event and handle it
    EventType currentEvent = EVENT_LOGIN;
    void (*eventHandler)() = NULL;

    switch (currentEvent) {
        case EVENT_LOGIN:
            eventHandler = handleLogin;
            break;
        case EVENT_LOGOUT:
            eventHandler = handleLogout;
            break;
        case EVENT_ERROR:
            eventHandler = handleError;
            break;
    }

    // Dispatch the event
    if (eventHandler != NULL) {
        eventDispatcher(currentEvent, eventHandler);
    }

    return 0;
}

 

Explanation

  • Enum EventType defines different types of events that our system can handle.
  • Function pointers like eventHandler are used to store the address of a function that should be called when a particular event occurs. This allows the event handling mechanism to be very flexible and easily extensible.
  • eventDispatcher function takes an event type and a function pointer. It simply calls the function pointed to by eventHandler. This simulates the core of an event-driven system where events are handled according to the function assigned to handle them.

This example can be extended with more complex handlers, different event types, and more sophisticated event dispatching logic. The use of function pointers here provides a clear separation between event dispatching and event handling, making the system more modular and maintainable.

728x90
반응형