首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C/C++ 函式回調實作:函式指標結構體成員模式

     編輯:更多程式設計知識

前言

C 語言無原生閉包或委派,但透過函式指標作為結構體成員,即可實現「註冊回調 → 觸發執行」模式,廣泛用於事件驅動、驅動程式、GUI 框架。

核心模式:回調結構體


#include 

// 1. 定義回調函式簽名
typedef void (*CallbackFunc)(const char* message);

// 2. 結構體持有函式指標
typedef struct {
    CallbackFunc callback;  // 回調槽位
    void* user_data;        // 可選:使用者上下文
} EventHandler;

// 3. 具體回調實作
void onEvent(const char* msg) {
    printf("[Event] %s\n", msg);
}

void onError(const char* msg) {
    fprintf(stderr, "[ERROR] %s\n", msg);
}

// 4. 觸發器:檢查非 NULL 後呼叫
void triggerEvent(EventHandler* handler, const char* msg) {
    if (handler && handler->callback) {
        handler->callback(msg);
    }
}

int main() {
    EventHandler h1 = { .callback = onEvent };
    EventHandler h2 = { .callback = onError };

    triggerEvent(&h1, "System started");
    triggerEvent(&h2, "Disk full");

    // 動態切換回調
    h1.callback = onError;
    triggerEvent(&h1, "Switched to error handler");

    return 0;
}

進階:攜帶上下文資料


typedef struct {
    int id;
    char name[32];
} Sensor;

void sensorCallback(const char* msg, void* ctx) {
    Sensor* s = (Sensor*)ctx;
    printf("[Sensor %d:%s] %s\n", s->id, s->name, msg);
}

typedef struct {
    void (*callback)(const char*, void*);
    void* user_data;
} CallbackWithContext;

int main() {
    Sensor s1 = {1, "Temp"};
    CallbackWithContext cb = {sensorCallback, &s1};
    cb.callback("Reading: 25.6°C", cb.user_data);
    return 0;
}

實戰場景:簡易事件循環


#define MAX_HANDLERS 10

typedef struct {
    int event_type;
    EventHandler handlers[MAX_HANDLERS];
    int count;
} EventDispatcher;

void dispatch(EventDispatcher* disp, int type, const char* msg) {
    for (int i = 0; i < disp->count; i++) {
        if (disp->handlers[i].callback)  // 簡易:同類型全觸發
            disp->handlers[i].callback(msg);
    }
}

// 註冊
int subscribe(EventDispatcher* disp, int type, CallbackFunc cb) {
    if (disp->count >= MAX_HANDLERS) return -1;
    disp->handlers[disp->count++] = (EventHandler){cb, NULL};
    return 0;
}

C++ 現代化替代:std::function + lambda

C++11 後推薦使用型別安全、支援捕獲的 std::function:


#include 
#include 
#include 

class EventBus {
    using Handler = std::function;
    std::vector handlers_;
public:
    void subscribe(Handler h) { handlers_.push_back(std::move(h)); }
    void publish(const std::string& msg) {
        for (auto& h : handlers_) if (h) h(msg);
    }
};

int main() {
    EventBus bus;
    bus.subscribe([](auto msg){ std::cout << "[Lambda] " << msg << "\n"; });
    bus.subscribe([](auto msg){ std::cerr << "[Error] " << msg << "\n"; });
    bus.publish("Hello Callback");
    return 0;
}

關鍵比較

特性C 函式指標C++ std::function
型別安全靠開發者簽名一致編譯期強制檢查
狀態捕獲需手動傳 void*Lambda 自動捕獲
效能極低開銷 (單指標)小型物件優化,略高
可攜性純 C89 相容需 C++11

結語

「結構體 + 函式指標」是 C 語言實現回調/多型的基石模式。理解其機制有助於閱讀 Linux 核心、嵌入式驅動、GUI 庫 (GTK/Qt 早期) 代碼。C++ 專案應優先使用 std::function,但在與 C 介面互操作、極度資源受限環境,C 風格回調仍是最佳選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved