在嵌入式软件中,使用数组实现责任链模式是一种高效且易于维护的设计方法。相比链表,数组实现具有内存连续、访问速度快、代码简洁等优势,非常适合资源受限且对实时性要求高的嵌入式环境
为什么在嵌入式中用数组实现责任链?
1.内存连续,缓存友好:数组在内存中是连续存储的,遍历时CPU缓存命中率高,执行效率优于链表。
2.无需动态内存分配:可以预先定义固定大小的数组,避免使用 malloc/free,降低内存碎片风险。
3.代码简洁,易于调试:使用 for 循环遍历,逻辑清晰,调试时更容易追踪执行流程。
4.适合静态配置:嵌入式系统通常在编译时确定功能模块,数组非常适合这种"静态组装、动态执行"的模式。
以串口协议解析为例,实现一个基于数组的责任链
第一步:定义统一的处理器接口
c
// protocol_handler.h
#ifndef PROTOCOL_HANDLER_H
#define PROTOCOL_HANDLER_H
#include <stdint.h>
#include <stdbool.h>
// 处理结果
typedef enum {
HANDLER_OK, // 成功处理,链条终止
HANDLER_PASS, // 无法处理,继续下一个
HANDLER_ERROR // 发生错误,终止链条
} HandlerResult;
// 处理器函数类型
typedef HandlerResult (*HandlerFunc)(uint8_t* data, int len);
// 责任链最大长度
#define MAX_HANDLERS 8
// 责任链结构体
typedef struct {
HandlerFunc handlers[MAX_HANDLERS]; // 处理器函数数组
int count; // 当前处理器数量
} ProtocolChain;
// 初始化责任链
void chain_init(ProtocolChain* chain);
// 添加处理器
bool chain_add_handler(ProtocolChain* chain, HandlerFunc handler);
// 执行责任链
HandlerResult chain_execute(ProtocolChain* chain, uint8_t* data, int len);
#endif
第二步:实现责任链核心逻辑
c
// protocol_handler.c
#include "protocol_handler.h"
#include <string.h>
// 初始化
void chain_init(ProtocolChain* chain) {
memset(chain->handlers, 0, sizeof(chain->handlers));
chain->count = 0;
}
// 添加处理器
bool chain_add_handler(ProtocolChain* chain, HandlerFunc handler) {
if (chain->count >= MAX_HANDLERS) {
return false; // 数组已满
}
chain->handlers[chain->count++] = handler;
return true;
}
// 执行责任链
HandlerResult chain_execute(ProtocolChain* chain, uint8_t* data, int len) {
for (int i = 0; i < chain->count; i++) {
HandlerResult result = chain->handlers[i](data, len);
if (result != HANDLER_PASS) {
return result; // OK 或 ERROR 都终止链条
}
}
return HANDLER_PASS; // 所有处理器都未处理
}
第三步:实现具体协议处理器
c
// modbus_handler.c
#include "protocol_handler.h"
#include <stdio.h>
// 简单的CRC校验函数(示例)
static bool check_crc(uint8_t* data, int len) {
// 实际项目中应实现真实CRC算法
return len >= 4; // 简化判断
}
// Modbus协议处理器
HandlerResult handle_modbus(uint8_t* data, int len) {
if (len >= 4 && data == 0x01 && check_crc(data, len)) {
printf("Modbus frame received: ");
for (int i = 0; i < len; i++) {
printf("%02X ", data[i]);
}
printf("\n");
// 执行Modbus命令解析...
return HANDLER_OK;
}
return HANDLER_PASS; // 不是Modbus帧,交给下一个
}
c
// custom_handler.c
#include "protocol_handler.h"
#include <stdio.h>
// 自定义协议处理器
HandlerResult handle_custom(uint8_t* data, int len) {
if (len >= 3 && data == 0xAA) {
printf("Custom protocol: 0x%02X 0x%02X 0x%02X\n",
data, data, data);
// 处理自定义协议...
return HANDLER_OK;
}
return HANDLER_PASS;
}
```<websource>source_group_web_1</websource>
#### 第四步:组装和使用责任链
```c
// main.c
#include "protocol_handler.h"
#include <stdio.h>
// 外部声明处理器
extern HandlerResult handle_modbus(uint8_t*, int);
extern HandlerResult handle_custom(uint8_t*, int);
int main() {
ProtocolChain chain;
// 1. 初始化责任链
chain_init(&chain);
// 2. 静态组装责任链(编译时确定顺序)
chain_add_handler(&chain, handle_custom); // 先检查自定义协议
chain_add_handler(&chain, handle_modbus); // 再检查Modbus
// 3. 模拟串口接收数据
uint8_t frame1[] = {0xAA, 0x01, 0x02}; // 自定义协议
uint8_t frame2[] = {0x01, 0x03, 0x00, 0x00}; // Modbus协议
uint8_t frame3[] = {0xFF, 0xFF, 0xFF}; // 未知协议
printf("--- Processing Frame 1 ---\n");
chain_execute(&chain, frame1, sizeof(frame1));
printf("\n--- Processing Frame 2 ---\n");
chain_execute(&chain, frame2, sizeof(frame2));
printf("\n--- Processing Frame 3 ---\n");
chain_execute(&chain, frame3, sizeof(frame3));
return 0;
}
数组实现 vs 链表实现
| 特性 | 数组实现 | 链表实现 |
|---|---|---|
| 内存使用 | 静态分配,无碎片 | 动态分配,可能碎片化 |
| 执行效率 | 高(缓存友好) | 较低(指针跳转) |
| 代码复杂度 | 简单(for循环) | 复杂(指针管理) |
| 调试难度 | 容易(索引清晰) | 较难(指针追踪) |
| 扩展性 | 固定大小,编译时确定 | 运行时动态添加 |
| 适用场景 | 协议解析、过滤器、校验链 | 动态审批流、插件系统 |