C语言拆分十六进制数据缓冲区中指令与对应数值的实现方法
C语言十六进制指令缓冲区解析实现
核心处理逻辑
原始缓冲区是按\r\n(对应十六进制值0x0D、0x0A)分隔的ASCII格式指令集,解析按3个阶段执行:
- 按换行符拆分独立指令行,过滤无效空行
- 从行首提取连续大写字母(含下划线,适配
PARTIAL_CUTTER这类带下划线的指令)作为指令关键字,遇到空格即停止提取 - 从关键字后续内容中过滤单位(
mm)、分隔符(逗号、空格),提取所有数值并和当前指令绑定存储
完整实现代码
#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> // 单条指令最大支持参数数量 #define MAX_PARAM_CNT 4 // 指令名最大长度 #define MAX_CMD_LEN 32 // 最大支持指令条数 #define MAX_CMD_NUM 16 typedef struct { char cmd_name[MAX_CMD_LEN]; float params[MAX_PARAM_CNT]; uint8_t param_cnt; } CmdStruct; int main() { uint8_t data_buff[] = {0x53, 0x49, 0x5A, 0x45, 0x20, 0x37, 0x36, 0x2E, 0x32, 0x20, 0x6D, 0x6D, 0x2C, 0x20, 0x35, 0x30, 0x2E, 0x38, 0x20, 0x6D, 0x6D, 0x0D, 0x0A, 0x42, 0x4C, 0x49, 0x4E, 0x45, 0x20, 0x33, 0x20, 0x6D, 0x6D, 0x2C, 0x20, 0x30, 0x20, 0x6D, 0x6D, 0x0D, 0x0A, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4F, 0x4E, 0x20, 0x30, 0x2C, 0x30, 0x0D, 0x0A, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, 0x4E, 0x43, 0x45, 0x20, 0x30, 0x2C, 0x30, 0x0D, 0x0A, 0x4F, 0x46, 0x46, 0x53, 0x45, 0x54, 0x20, 0x30, 0x20, 0x6D, 0x6D, 0x0D, 0x0A, 0x53, 0x45, 0x54, 0x20, 0x50, 0x45, 0x45, 0x4C, 0x20, 0x4F, 0x46, 0x46, 0x0D, 0x0A, 0x53, 0x45, 0x54, 0x20, 0x43, 0x55, 0x54, 0x54, 0x45, 0x52, 0x20, 0x4F, 0x46, 0x46, 0x0D, 0x0A, 0x53, 0x45, 0x54, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, 0x41, 0x4C, 0x5F, 0x43, 0x55, 0x54, 0x54, 0x45, 0x52, 0x20, 0x4F, 0x46, 0x46, 0x0D, 0x0A}; CmdStruct cmd_list[MAX_CMD_NUM] = {0}; uint8_t cmd_total = 0; char line_buff[128] = {0}; uint16_t line_idx = 0; uint16_t buff_len = sizeof(data_buff); // 按换行拆分每行指令 for (uint16_t i = 0; i < buff_len; i++) { if (data_buff[i] == 0x0D) { // 遇到\r,判定一行结束 i++; // 跳过后续的\n(0x0A) line_buff[line_idx] = '\0'; if (line_idx > 0 && cmd_total < MAX_CMD_NUM) { // 解析当前行内容 char* p = line_buff; uint8_t name_idx = 0; // 提取指令名:大写字母/下划线均计入,直到遇到空格停止 while ((*p >= 'A' && *p <= 'Z') || *p == '_') { cmd_list[cmd_total].cmd_name[name_idx++] = *p++; } cmd_list[cmd_total].cmd_name[name_idx] = '\0'; p++; // 跳过指令名后第一个空格 // 提取数值参数 char num_buff[16] = {0}; uint8_t num_idx = 0; uint8_t param_cnt = 0; while (*p != '\0' && param_cnt < MAX_PARAM_CNT) { if ((*p >= '0' && *p <= '9') || *p == '.') { num_buff[num_idx++] = *p; } else { if (num_idx > 0) { num_buff[num_idx] = '\0'; cmd_list[cmd_total].params[param_cnt++] = atof(num_buff); num_idx = 0; } } p++; } // 处理行尾最后一个参数 if (num_idx > 0 && param_cnt < MAX_PARAM_CNT) { num_buff[num_idx] = '\0'; cmd_list[cmd_total].params[param_cnt++] = atof(num_buff); } cmd_list[cmd_total].param_cnt = param_cnt; cmd_total++; } // 重置行缓存 memset(line_buff, 0, sizeof(line_buff)); line_idx = 0; } else { line_buff[line_idx++] = data_buff[i]; } } // 打印解析结果验证 for (uint8_t i = 0; i < cmd_total; i++) { printf("指令: %s, 参数数量: %u, 参数值: ", cmd_list[i].cmd_name, cmd_list[i].param_cnt); for (uint8_t j = 0; j < cmd_list[i].param_cnt; j++) { printf("%.1f ", cmd_list[i].params[j]); } printf("\n"); } getchar(); return 0; }
解析输出结果
运行后可得到结构化的指令数据,和预期完全匹配:
指令: SIZE, 参数数量: 2, 参数值: 76.2 50.8 指令: BLINE, 参数数量: 2, 参数值: 3.0 0.0 指令: DIRECTION, 参数数量: 2, 参数值: 0.0 0.0 指令: REFERENCE, 参数数量: 2, 参数值: 0.0 0.0 指令: OFFSET, 参数数量: 1, 参数值: 0.0 指令: SET, 参数数量: 0, 参数值: 指令: SET, 参数数量: 0, 参数值: 指令: SET, 参数数量: 0, 参数值:
注:SET类指令(PEEL OFF/CUTTER OFF等)参数为开关状态字符串,无数值参数,因此参数计数为0。如果需要存储字符串参数,可在结构体中新增字符串参数数组成员扩展即可。
内容的提问来源于stack exchange,提问作者Akshay
相关产品推荐
相关产品推荐

