【嵌入式C快捷键设计】表驱动法实现

表驱动法的优势

这种设计实现了数据驱动的编程模式,将配置信息(快捷键映射)与执行逻辑分离,是嵌入式系统中实用的设计模式。具有维护性好、代码复用高、拓展性好等优点。

表驱动法的原理

将程序逻辑从代码转移到数据,通过查询数据表来决定程序行为,而不是通过复杂的控制逻辑。

表驱动法的核心原理是:通过数据配置来代替硬编码的逻辑判断,利用函数指针机制实现动态调用。

案例实战

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且无参数的函数。

相关推荐
(Charon)13 小时前
【C++】线程安全队列(二):生产者消费者模型与 condition_variable 阻塞等待
c语言·开发语言·c++
AustinXu15 小时前
从 Claude Code 到 Claude Tag,Harness Engineering 走到了组织这一层
设计模式·团队管理
剧中有戏15 小时前
单例模式从入门到精通:一个数据库连接池的完整剖析
设计模式
胡萝卜术15 小时前
编译期与运行期的双重防线:从 TypeScript 类型之争到 LLM 输出的自动化择优
前端·设计模式·面试
货拉拉技术15 小时前
重塑 Agent 度量衡:基于 LLM-as-a-Judge 的离线评估体系与实践
算法·设计模式
wuminyu15 小时前
JDK21解决虚拟线程IO阻塞原理剖析
java·linux·c语言·jvm·c++
KhalilRuan16 小时前
设计模式小记
设计模式
卡牌RWA研究院16 小时前
Relique:一张精品卡牌如何从收藏品变成可交易的链上资产?
设计模式·金融·区块链·创业创新
MC皮蛋侠客18 小时前
TDengine C++ 系列(5):C/C++ 连接器——连接管理与查询 API
c语言·c++·tdengine
天空'之城18 小时前
C 语言工业级通用组件手写 27:配置参数管理组件
c语言·eeprom·参数管理·工业级组件·掉电存储