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

C 語言函數指針數組與驅動表模式:消除 switch-case 降低圈復雜度

     編輯:關於C

從函數指針到函數指針數組

函數指針數組將多個同簽名函數的入口地址存儲在數組中,通過下標直接調用,實現「數據驅動邏輯」。

基礎示例:四則運算

int Sum(int a, int b) { return a + b; }
int Sub(int a, int b) { return a - b; }
int Mul(int a, int b) { return a * b; }
int Div(int a, int b) { return b ? a / b : 0; }

typedef int (*pfFun)(int, int);

int TestFun(int a, int b, pfFun pf) {
    return pf(a, b);
}

int main() {
    pfFun ops[] = {Sum, Sub, Mul, Div};
    printf("%d\n", TestFun(20, 10, ops[0]));  // 30
    printf("%d\n", TestFun(20, 10, ops[1]));  // 10
    return 0;
}

驅動表模式:替代 switch-case

傳統 switch 版(圈復雜度高)

typedef enum { ADD=0, SUB, MUL, DIV, OP_MAX } OpCode;

int CalcSwitch(int a, int b, OpCode op) {
    switch (op) {
        case ADD: return Sum(a, b);
        case SUB: return Sub(a, b);
        case MUL: return Mul(a, b);
        case DIV: return Div(a, b);
        default: return -1;
    }
}

缺點:
• 每新增運算需修改 enum、switch、case
• 圈復雜度 V(G) = 分支數 + 1,隨運算增多線性增長
• 違反開閉原則(OCP)

驅動表版(圈復雜度恆為 1)

int CalcTable(int a, int b, OpCode op) {
    if (op >= OP_MAX) return -1;
    static const pfFun table[OP_MAX] = {Sum, Sub, Mul, Div};
    return table[op](a, b);
}

優勢:
• 新增運算:只需在 table 末尾追加函數指針,enum 自動擴展
• 圈復雜度 = 1(單一路徑)
• O(1) 查找,無分支預測失敗
• 邏輯與數據分離,利於單元測試

圈復雜度科普

McCabe 圈復雜度 V(G) = E - N + 2P(邊 - 節點 + 2×連通分量)。直觀理解:判定節點數 + 1。
• if/else、while、for、case、catch、&&/|| 短路均計 1 分
• 建議單函數 V(G) ≤ 10,超過需重構

工程級驅動表擴展

typedef struct {
    OpCode code;
    const char *name;
    pfFun handler;
    const char *desc;
} OpEntry;

static const OpEntry g_op_table[] = {
    {ADD, "add", Sum, "加法"},
    {SUB, "sub", Sub, "減法"},
    {MUL, "mul", Mul, "乘法"},
    {DIV, "div", Div, "除法"},
    // 新增只需在這裡添加一行
};

int CalcByName(int a, int b, const char *name) {
    for (size_t i = 0; i < sizeof(g_op_table)/sizeof(g_op_table[0]); i++)
        if (strcmp(g_op_table[i].name, name) == 0)
            return g_op_table[i].handler(a, b);
    return -1;
}

進一步支持:
• 字符串名稱調度(如 RPC、命令行解析)
• 運行時動態註冊(插件架構)
• 元數據驅動文檔生成

適用場景與局限

場景適合驅動表?說明
固定枚舉、同簽名、高頻調用✅ 極佳編譯期綁定,零開銷
需運行時動態增減✅ 配合函數指針鏈表/哈希表插件系統、熱加載
參數類型/個數不一致❌需統一為 void* + 上下文結構體
極少分支(≤3)且穩定⚠ 可不必switch 更直觀
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved