表驱动法的优势
这种设计实现了数据驱动的编程模式,将配置信息(快捷键映射)与执行逻辑分离,是嵌入式系统中实用的设计模式。具有维护性好、代码复用高、拓展性好等优点。
表驱动法的原理
将程序逻辑从代码转移到数据,通过查询数据表来决定程序行为,而不是通过复杂的控制逻辑。
表驱动法的核心原理是:通过数据配置来代替硬编码的逻辑判断,利用函数指针机制实现动态调用。
案例实战
cpp
#include <stdio.h>
#include <string.h>
#include <stdint.h>
// 类型定义
typedef int32_t (*T_SHORTCUT_CALLBACK)(void);
#define SHORTCUT_MAX_ID_LEN 20
#define SHORTCUT_END_STR "end"
// 快捷键列表结构体
typedef struct {
char id[SHORTCUT_MAX_ID_LEN + 1];
T_SHORTCUT_CALLBACK cb;
const char *description; // 添加描述信息便于演示
} T_SHORTCUT_LIST;
// 定义返回码
typedef enum {
eMENU_RESULT_SUCCESS = 0,
eMENU_RESULT_FAIL = -1
} menu_result_t;
// 模拟权限验证函数
int app_is_second_user_verify(void) {
return 0; // 假设总是有权限
}
void app_menu_exit_flag_clear(void) {
printf("清理菜单退出标志\n");
}
// 具体的快捷键处理函数
int32_t save_function(void) {
printf("执行保存操作...\n");
printf("文件保存成功!\n");
return eMENU_RESULT_SUCCESS;
}
int32_t print_function(void) {
printf("执行打印操作...\n");
printf("文档打印完成!\n");
return eMENU_RESULT_SUCCESS;
}
int32_t help_function(void) {
printf(" 显示帮助信息:\n");
printf(" save - 保存文件\n");
printf(" print - 打印文档\n");
printf(" help - 显示帮助\n");
printf(" time - 显示时间\n");
printf(" exit - 退出程序\n");
return eMENU_RESULT_SUCCESS;
}
int32_t time_function(void) {
printf(" 当前时间: 2024-01-01 12:00:00\n");
return eMENU_RESULT_SUCCESS;
}
int32_t exit_function(void) {
printf(" 感谢使用,再见!\n");
return eMENU_RESULT_SUCCESS;
}
// 快捷键映射表
static const T_SHORTCUT_LIST app_shortcut_list[] = {
{"save", save_function, "保存文件"},
{"print", print_function, "打印文档"},
{"help", help_function, "显示帮助"},
{"time", time_function, "显示时间"},
{"exit", exit_function, "退出程序"},
{SHORTCUT_END_STR, NULL, "结束标记"} // 必须放在最后!
};
// 快捷键处理函数
int8_t app_shortcut_handle(const char *key_buff) {
uint16_t i = 0;
printf("\n 正在查找快捷键: '%s'\n", key_buff);
while(1) {
// 检查是否匹配当前快捷键
if(strcmp(app_shortcut_list[i].id, key_buff) == 0) {
printf(" 找到匹配的快捷键: %s -> %s\n",
app_shortcut_list[i].id, app_shortcut_list[i].description);
// 执行回调函数
printf(" 开始执行回调函数...\n");
int32_t ret = app_shortcut_list[i].cb();
printf(" 函数执行结果: %d\n", ret);
return ret;
}
// 检查是否到达列表末尾
else if(strcmp(app_shortcut_list[i].id, SHORTCUT_END_STR) == 0) {
printf(" 未找到匹配的快捷键: '%s'\n", key_buff);
printf(" 可用命令: save, print, help, time, exit\n");
return eMENU_RESULT_FAIL;
}
i++;
}
}
// 显示欢迎信息
void show_welcome(void) {
printf("=====================================\n");
printf(" 表驱动法快捷键演示程序\n");
printf("=====================================\n");
printf("这是一个演示表驱动法处理快捷键的示例\n");
printf("使用 scanf 接收用户输入\n\n");
}
// 显示快捷键列表
void show_shortcut_list(void) {
printf(" 可用的快捷键列表:\n");
printf("-----------------------------\n");
int i = 0;
while(strcmp(app_shortcut_list[i].id, SHORTCUT_END_STR) != 0) {
printf(" %-8s - %s\n",
app_shortcut_list[i].id,
app_shortcut_list[i].description);
i++;
}
printf("-----------------------------\n");
}
int main(void) {
char input[SHORTCUT_MAX_ID_LEN + 1];
show_welcome();
show_shortcut_list();
// 主循环
while(1) {
printf("\n 请输入快捷键 (输入 exit 退出): ");
// 使用scanf接收输入
if(scanf("%20s", input) != 1) {
printf(" 输入错误,请重新输入\n");
while(getchar() != '\n'); // 清空输入缓冲区
continue;
}
// 处理快捷键
int8_t result = app_shortcut_handle(input);
if(strcmp(input, "exit") == 0) {
break; // 退出程序
}
if(result == eMENU_RESULT_FAIL) {
printf("快捷键处理失败\n");
}
}
printf("\n=====================================\n");
printf(" 程序正常结束\n");
printf("=====================================\n");
return 0;
}
-
typedef
:用于定义新类型的关键字。 -
int32_t
:函数的返回值类型,通常是一个32位有符号整数(需要包含stdint.h
头文件)。 -
(*T_SHORTCUT_CALLBACK)
:T_SHORTCUT_CALLBACK
是一个指针,指向函数。 -
(void)
:函数的参数列表,这里表示没有参数。
所以,这个定义之后,我们可以使用T_SHORTCUT_CALLBACK
来声明一个函数指针变量,该变量可以指向任何返回值类型为int32_t
且无参数的函数。