嵌入式終端(如手機模組)功能日益複雜,需支援遠程配置:不同客戶、不同時刻、不同地點需要不同功能組合。硬編碼 if-else 或 switch-case 導致代碼膨脹、難以維護、無法熱更新。表驅動(Table-Driven)+ 動態鏈表掛載 是經典解法。
typedef enum { RET_SUCCESS, RET_FAIL, RET_INVALID_DATA } NMCMD_RETURN;
typedef NMCMD_RETURN (*COMMAND_FUNCTION)(uint16_t cmd_id, const char *data, uint8_t len);
typedef struct _XNNM_CMDPROC {
struct _XNNM_CMDPROC *pNext; // 下一個模組處理器
COMMAND_FUNCTION fProc; // 模組入口函數
} XNNM_CMDPROC;
static XNNM_CMDPROC *g_cmd_list = NULL; // 全域鏈表頭
bool xnnm_LoadProc(COMMAND_FUNCTION proc) {
if (!proc) return false;
XNNM_CMDPROC *node = malloc(sizeof(*node));
if (!node) return false;
memset(node, 0, sizeof(*node));
node->fProc = proc;
node->pNext = g_cmd_list; // 頭插法,新模組優先處理
g_cmd_list = node;
return true;
}
bool xnnm_ExecProc(uint16_t cmd_id, const char *data, uint8_t len) {
for (XNNM_CMDPROC *cur = g_cmd_list; cur; cur = cur->pNext) {
if (cur->fProc(cmd_id, data, len) == RET_SUCCESS)
return true; // 責任鏈模式:第一個處理成功即停止
}
return false; // 所有模組均未處理
}
每個功能模組(如鎖機鎖卡)維護自己的 命令-處理函數映射表:
// 1. 定義具體命令處理函數
static NMCMD_RETURN nmcmd_lock_pin(uint16_t cmd, const char *data, uint8_t len) {
if (len < 1 || len > 2 || !is_digit_str(data, len)) return RET_INVALID_DATA;
locknv_enable_pin(atoi(data) ? 1 : 0);
return RET_SUCCESS;
}
// 2. 建立映射表(編譯期常數,二分查找優化可行)
static const struct { uint16_t cmd_id; COMMAND_FUNCTION func; } cmd_table[] = {
{ ID_NMCMD_LOCK_PIN, nmcmd_lock_pin },
{ ID_NMCMD_ENABLE_RAND_PIN, nmcmd_enable_rand_pin },
{ ID_NMCMD_SET_FIXED_PIN, nmcmd_fix_pin },
// ... 更多命令
{ 0, NULL } // 哨兵
};
// 3. 模組入口函數:查表分發
NMCMD_RETURN locknm_handlercmd(uint16_t cmd_id, const char *data, uint8_t len) {
for (int i = 0; cmd_table[i].func; i++) {
if (cmd_table[i].cmd_id == cmd_id)
return cmd_table[i].func(cmd_id, data, len);
}
return RET_FAIL; // 未知命令
}
// 4. 模組初始化:註冊到全域鏈表
void lock_init_proc(void) {
xnnm_LoadProc(locknm_handlercmd);
}
enum 或 #define)。COMMAND_FUNCTION)。cmd_table 並實作 xxx_handlercmd。xxx_init_proc() 掛載。零修改核心分發代碼,實現開閉原則(OCP)。
cmd_table 排序並用 bsearch 或完美哈希加速。priority 欄位,掛載時按優序插入。dlopen/LoadLibrary 實現 .so/.dll 熱插拔(高端 Linux/Android 平台)。表驅動將「控制流」轉化為「資料結構」,動態鏈表實現模組解耦與擴展。這是資源受限嵌入式系統實現靈活業務邏輯的經典模式,亦是「配置即代碼」思想在 C 語言層面的落地。