萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> 程式語言綜合

C/C++ 函式回呼實作:函式指標作為結構體成員實現註冊與回調

核心概念

C/C++ 無原生閉包,但可透過函式指標實現回呼:呼叫端將函式位址傳遞給被呼叫端,被呼叫端在適當時機透過指標間接呼叫。

最小可行範例

#include <stdio.h>

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

// 2. 結構體持有函式指標
struct Handler {
    CallbackFunc callback;
};

// 3. 實際業務邏輯
void doSomething(const char *job) {
    printf("處理工作: %s\n", job);
}

// 4. 註冊與觸發
int main() {
    struct Handler h;
    h.callback = doSomething;      // 註冊
    h.callback("something");       // 回呼執行
    return 0;
}

進階模式:參數化回呼上下文

typedef void (*CallbackEx)(void *ctx, const char *msg);

struct HandlerEx {
    CallbackEx callback;
    void *context;  // 攜帶任意上下文資料
};

void logger(void *ctx, const char *msg) {
    FILE *fp = (FILE*)ctx;
    fprintf(fp, "[LOG] %s\n", msg);
}

int main() {
    FILE *log = fopen("app.log", "a");
    struct HandlerEx h = { logger, log };
    h.callback(h.context, "系統啟動");
    fclose(log);
    return 0;
}

C++ 現代化寫法

#include <functional>
#include <iostream>

class EventDispatcher {
    std::function callback_;
public:
    void setCallback(std::function cb) { callback_ = cb; }
    void trigger(const std::string& msg) { if (callback_) callback_(msg); }
};

int main() {
    EventDispatcher disp;
    disp.setCallback([](const std::string& s){ std::cout << "Lambda: " << s << '\n'; });
    disp.trigger("Hello Callback");
    return 0;
}

應用場景對照表

場景C 風格C++ 現代
事件迴圈/訊號處理函式指標 + void* contextstd::function + lambda
排序/搜尋自訂比較qsort 比較函式指標std::sort + lambda
非同步完成通知回呼函式指標std::future / coroutine
插件架構函式表結構體介面類別 + 虛擬函式

常見坑與對策

  • 呼叫慣例不匹配:Windows API 需 __stdcall,確保宣告一致。
  • 生命週期管理:回呼捕獲的上下文指標必須在回呼執行時仍有效(智慧指標/引用計數)。
  • 執行緒安全:跨執行緒回呼需加鎖或使用無鎖佇列。
  • 例外傳播:C 回呼不支援 C++ 例外,跨語言邊界需捕獲轉碼。

函式指標回呼是系統程式設計的基石,掌握其 C 與 C++ 兩種風格,能靈活應對從嵌入式裝置到高階應用框架的各種非同步、事件驅動需求。

copyright © 萬盛學電腦網 all rights reserved